Compare commits

..

6 commits

Author SHA1 Message Date
Antoni
0b2b3a9852
Merge 0e1691ee4c into c65e20d77b 2025-05-30 12:54:40 +03:00
Gravita
c65e20d77b [FIX][EXPERIMENTAL] Full support UpdatesProvider 2025-05-30 16:49:55 +07:00
Gravita
e664c579a5 [FEATURE][EXPERIMENTAL] Full support UpdatesProvider 2025-05-30 16:22:31 +07:00
Gravita
1e4e1c5837 [FIX] Add writeLock for Client in launchserver.config.reload 2025-05-30 14:48:48 +07:00
Gravita
b8f6857ef2 [REFACTOR] Update create module api 2025-05-30 14:15:49 +07:00
Gravita
de844201b4 [FIX] Sentry LaunchServer module 2025-05-30 13:35:53 +07:00
26 changed files with 323 additions and 82 deletions

View file

@ -27,6 +27,7 @@
import pro.gravit.utils.command.CommandHandler; import pro.gravit.utils.command.CommandHandler;
import pro.gravit.utils.command.SubCommand; import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
@ -226,8 +227,15 @@ public void reload(ReloadType type) throws Exception {
if(!type.equals(ReloadType.NO_AUTH)) { if(!type.equals(ReloadType.NO_AUTH)) {
nettyServerSocketHandler.nettyServer.service.forEachActiveChannels((channel, wsHandler) -> { nettyServerSocketHandler.nettyServer.service.forEachActiveChannels((channel, wsHandler) -> {
Client client = wsHandler.getClient(); Client client = wsHandler.getClient();
if(client.auth != null) { var lock = client.writeLock();
lock.lock();
try {
if (client.auth_id == null) {
return;
}
client.auth = config.getAuthProviderPair(client.auth_id); client.auth = config.getAuthProviderPair(client.auth_id);
} finally {
lock.unlock();
} }
}); });
} }
@ -298,6 +306,12 @@ public void checkCertificateExpired() {
} }
} }
public Path createTempDirectory(String name) throws IOException {
var path = tmpDir.resolve(String.format("launchserver-%s-%s", name, SecurityHelper.randomStringToken()));
Files.createDirectories(path);
return path;
}
private LauncherBinary binary() { private LauncherBinary binary() {
LaunchServerLauncherExeInit event = new LaunchServerLauncherExeInit(this, null); LaunchServerLauncherExeInit event = new LaunchServerLauncherExeInit(this, null);
modulesManager.invokeEvent(event); modulesManager.invokeEvent(event);

View file

@ -9,7 +9,7 @@
import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent; import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import java.io.IOException; import java.io.*;
import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -153,6 +153,14 @@ public void upload(String updateName, Map<String, Path> files, boolean deleteAft
} }
} }
@Override
public OutputStream upload(String updateName, String file) throws IOException {
var path = resolveUpdateName(updateName);
var target = path.resolve(file);
IOHelper.createParentDirs(target);
return new FileOutputStream(target.toFile());
}
@Override @Override
public Map<String, Path> download(String updateName, List<String> files) { public Map<String, Path> download(String updateName, List<String> files) {
var path = resolveUpdateName(updateName); var path = resolveUpdateName(updateName);
@ -163,6 +171,39 @@ public Map<String, Path> download(String updateName, List<String> files) {
return map; return map;
} }
@Override
public void download(String updateName, Map<String, Path> files) throws IOException {
var path = resolveUpdateName(updateName);
for(var e : files.entrySet()) {
var source = path.resolve(e.getKey());
var target = e.getValue();
IOHelper.copy(source, target);
}
}
@Override
public InputStream download(String updateName, String path) throws IOException {
return new FileInputStream(resolveUpdateName(updateName).resolve(path).toFile());
}
@Override
public void move(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException {
for(var e : files.entrySet()) {
var source = resolveUpdateName(e.getKey().updateName()).resolve(e.getKey().path());
var target = resolveUpdateName(e.getValue().updateName()).resolve(e.getValue().path());
IOHelper.move(source, target);
}
}
@Override
public void copy(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException {
for(var e : files.entrySet()) {
var source = resolveUpdateName(e.getKey().updateName()).resolve(e.getKey().path());
var target = resolveUpdateName(e.getValue().updateName()).resolve(e.getValue().path());
IOHelper.copy(source, target);
}
}
@Override @Override
public void delete(String updateName, List<String> files) throws IOException { public void delete(String updateName, List<String> files) throws IOException {
var path = resolveUpdateName(updateName); var path = resolveUpdateName(updateName);

View file

@ -1,12 +1,22 @@
package pro.gravit.launchserver.auth.updates; package pro.gravit.launchserver.auth.updates;
import pro.gravit.launcher.core.hasher.HashedDir; import pro.gravit.launcher.core.hasher.HashedDir;
import pro.gravit.launcher.core.hasher.HashedEntry;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.ProviderMap; import pro.gravit.utils.ProviderMap;
import pro.gravit.utils.helper.IOHelper;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -38,7 +48,55 @@ public void sync() throws IOException {
public abstract void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException; public abstract void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException;
public abstract Map<String, Path> download(String updateName, List<String> files); public abstract OutputStream upload(String updateName, String file) throws IOException;
public void upload(String updateName, Path dir, boolean deleteAfterUpload) throws IOException {
if(!Files.isDirectory(dir)) {
throw new UnsupportedEncodingException(String.format("%s is not a directory", dir));
}
Map<String, Path> map = new HashMap<>();
IOHelper.walk(dir, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
map.put(dir.relativize(file).toString(), file);
return FileVisitResult.CONTINUE;
}
}, true);
upload(updateName, map, deleteAfterUpload);
}
public abstract Map<String, Path> download(String updateName, List<String> files) throws IOException;
public abstract void download(String updateName, Map<String, Path> files) throws IOException;
public abstract InputStream download(String updateName, String path) throws IOException;
public abstract void move(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException;
public void move(String updateName, String newUpdateName) throws IOException {
create(newUpdateName);
var updatesDir = getUpdatesDir(updateName);
Map<UpdateNameAndFile, UpdateNameAndFile> map = new HashMap<>();
updatesDir.walk("/", (path, name, entry) -> {
map.put(UpdateNameAndFile.of(updateName, path), UpdateNameAndFile.of(newUpdateName, path));
return HashedDir.WalkAction.CONTINUE;
});
move(map);
delete(updateName);
}
public abstract void copy(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException;
public void copy(String updateName, String newUpdateName) throws IOException {
create(newUpdateName);
var updatesDir = getUpdatesDir(updateName);
Map<UpdateNameAndFile, UpdateNameAndFile> map = new HashMap<>();
updatesDir.walk("/", (path, name, entry) -> {
map.put(UpdateNameAndFile.of(updateName, path), UpdateNameAndFile.of(newUpdateName, path));
return HashedDir.WalkAction.CONTINUE;
});
copy(map);
}
public abstract void delete(String updateName, List<String> files) throws IOException; public abstract void delete(String updateName, List<String> files) throws IOException;
@ -49,4 +107,10 @@ public void sync() throws IOException {
public void close() { public void close() {
} }
public record UpdateNameAndFile(String updateName, String path) {
public static UpdateNameAndFile of(String updateName, String path) {
return new UpdateNameAndFile(updateName, path);
}
}
} }

View file

@ -5,6 +5,7 @@
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.base.Launcher; import pro.gravit.launcher.base.Launcher;
import pro.gravit.launcher.base.Downloader; import pro.gravit.launcher.base.Downloader;
import pro.gravit.launcher.core.hasher.HashedDir;
import pro.gravit.launchserver.HttpRequester; import pro.gravit.launchserver.HttpRequester;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
@ -44,7 +45,12 @@ public void invoke(String... args) throws Exception {
String versionName = args[0]; String versionName = args[0];
String dirName = IOHelper.verifyFileName(args.length > 1 ? args[1] : "assets"); String dirName = IOHelper.verifyFileName(args.length > 1 ? args[1] : "assets");
String type = args.length > 2 ? args[2] : "mojang"; String type = args.length > 2 ? args[2] : "mojang";
Path assetDir = server.updatesDir.resolve(dirName); Path assetDir = server.createTempDirectory("assets");
var updatesDir = server.config.updatesProvider.getUpdatesDir(dirName);
if(updatesDir == null) {
updatesDir = new HashedDir();
server.config.updatesProvider.create(dirName);
}
// Create asset dir // Create asset dir
if (Files.notExists(assetDir)) { if (Files.notExists(assetDir)) {
@ -91,14 +97,8 @@ public void invoke(String... args) throws Exception {
hash = hash.substring(0, 2) + "/" + hash; hash = hash.substring(0, 2) + "/" + hash;
var size = value.get("size").getAsLong(); var size = value.get("size").getAsLong();
var path = "objects/" + hash; var path = "objects/" + hash;
var target = assetDir.resolve(path); if (updatesDir.tryFindRecursive(path).isFound()) {
if (Files.exists(target)) { continue;
long fileSize = Files.size(target);
if (fileSize != size) {
logger.warn("File {} corrupted. Size {}, expected {}", target, size, fileSize);
} else {
continue;
}
} }
toDownload.add(new Downloader.SizedFile(hash, path, size)); toDownload.add(new Downloader.SizedFile(hash, path, size));
} }
@ -112,6 +112,8 @@ public void invoke(String... args) throws Exception {
server.mirrorManager.downloadZip(assetDir, "assets/%s.zip", versionName); server.mirrorManager.downloadZip(assetDir, "assets/%s.zip", versionName);
} }
server.config.updatesProvider.upload(dirName, assetDir, true);
// Finished // Finished
server.syncUpdatesDir(Collections.singleton(dirName)); server.syncUpdatesDir(Collections.singleton(dirName));
logger.info("Asset successfully downloaded: '{}'", dirName); logger.info("Asset successfully downloaded: '{}'", dirName);

View file

@ -42,7 +42,8 @@ public void invoke(String... args) throws IOException, CommandException {
//Version version = Version.byName(args[0]); //Version version = Version.byName(args[0]);
String versionName = args[0]; String versionName = args[0];
String dirName = IOHelper.verifyFileName(args[1] != null ? args[1] : args[0]); String dirName = IOHelper.verifyFileName(args[1] != null ? args[1] : args[0]);
Path clientDir = server.updatesDir.resolve(dirName); Path clientDir = server.createTempDirectory("client");
server.config.updatesProvider.create(dirName);
boolean isMirrorClientDownload = false; boolean isMirrorClientDownload = false;
if (args.length > 2) { if (args.length > 2) {
@ -97,6 +98,7 @@ public void invoke(String... args) throws IOException, CommandException {
} }
} }
server.config.profileProvider.addProfile(clientProfile); server.config.profileProvider.addProfile(clientProfile);
server.config.updatesProvider.upload(dirName, clientDir, true);
// Finished // Finished
server.syncProfilesDir(); server.syncProfilesDir();

View file

@ -19,6 +19,8 @@
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public final class IndexAssetCommand extends Command { public final class IndexAssetCommand extends Command {
public static final String INDEXES_DIR = "indexes"; public static final String INDEXES_DIR = "indexes";
@ -54,24 +56,21 @@ public void invoke(String... args) throws Exception {
String inputAssetDirName = IOHelper.verifyFileName(args[0]); String inputAssetDirName = IOHelper.verifyFileName(args[0]);
String indexFileName = IOHelper.verifyFileName(args[1]); String indexFileName = IOHelper.verifyFileName(args[1]);
String outputAssetDirName = IOHelper.verifyFileName(args[2]); String outputAssetDirName = IOHelper.verifyFileName(args[2]);
Path inputAssetDir = server.updatesDir.resolve(inputAssetDirName); Path inputAssetDir = Path.of(inputAssetDirName);
Path outputAssetDir = server.updatesDir.resolve(outputAssetDirName); Map<String, Path> uploadMap = new HashMap<>();
if (outputAssetDir.equals(inputAssetDir))
throw new CommandException("Unindexed and indexed asset dirs can't be same");
// Create new asset dir
logger.info("Creating indexed asset dir: '{}'", outputAssetDirName);
Files.createDirectory(outputAssetDir);
// Index objects // Index objects
JsonObject objects = new JsonObject(); JsonObject objects = new JsonObject();
logger.info("Indexing objects"); logger.info("Indexing objects");
IOHelper.walk(inputAssetDir, new IndexAssetVisitor(objects, inputAssetDir, outputAssetDir), false); IOHelper.walk(inputAssetDir, new IndexAssetVisitor(objects, inputAssetDir, uploadMap), false);
server.config.updatesProvider.upload(outputAssetDirName, uploadMap, false);
// Write index file // Write index file
logger.info("Writing asset index file: '{}'", indexFileName); logger.info("Writing asset index file: '{}'", indexFileName);
try (BufferedWriter writer = IOHelper.newWriter(resolveIndexFile(outputAssetDir, indexFileName))) { var indexFile = resolveIndexFile(Path.of(""), indexFileName);
try (BufferedWriter writer = IOHelper.newWriter(server.config.updatesProvider.upload(outputAssetDirName, indexFile.toString()))) {
JsonObject result = new JsonObject(); JsonObject result = new JsonObject();
result.add("objects", objects); result.add("objects", objects);
writer.write(Launcher.gsonManager.gson.toJson(result)); writer.write(Launcher.gsonManager.gson.toJson(result));
@ -95,12 +94,12 @@ public IndexObject(long size, String hash) {
private final class IndexAssetVisitor extends SimpleFileVisitor<Path> { private final class IndexAssetVisitor extends SimpleFileVisitor<Path> {
private final JsonObject objects; private final JsonObject objects;
private final Path inputAssetDir; private final Path inputAssetDir;
private final Path outputAssetDir; private final Map<String, Path> uploadMap;
private IndexAssetVisitor(JsonObject objects, Path inputAssetDir, Path outputAssetDir) { private IndexAssetVisitor(JsonObject objects, Path inputAssetDir, Map<String, Path> uploadMap) {
this.objects = objects; this.objects = objects;
this.inputAssetDir = inputAssetDir; this.inputAssetDir = inputAssetDir;
this.outputAssetDir = outputAssetDir; this.uploadMap = uploadMap;
} }
@Override @Override
@ -112,7 +111,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
String digest = SecurityHelper.toHex(SecurityHelper.digest(DigestAlgorithm.SHA1, file)); String digest = SecurityHelper.toHex(SecurityHelper.digest(DigestAlgorithm.SHA1, file));
IndexObject obj = new IndexObject(attrs.size(), digest); IndexObject obj = new IndexObject(attrs.size(), digest);
objects.add(name, Launcher.gsonManager.gson.toJsonTree(obj)); objects.add(name, Launcher.gsonManager.gson.toJsonTree(obj));
IOHelper.copy(file, resolveObjectFile(outputAssetDir, digest)); uploadMap.put(resolveObjectFile(Path.of(""), digest).toString(), file);
// Continue visiting // Continue visiting
return super.visitFile(file, attrs); return super.visitFile(file, attrs);

View file

@ -5,6 +5,7 @@
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.core.hasher.HashedDir;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.CommandException; import pro.gravit.utils.command.CommandException;
@ -14,6 +15,7 @@
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
public final class UnindexAssetCommand extends Command { public final class UnindexAssetCommand extends Command {
@ -39,10 +41,11 @@ public void invoke(String... args) throws Exception {
String inputAssetDirName = IOHelper.verifyFileName(args[0]); String inputAssetDirName = IOHelper.verifyFileName(args[0]);
String indexFileName = IOHelper.verifyFileName(args[1]); String indexFileName = IOHelper.verifyFileName(args[1]);
String outputAssetDirName = IOHelper.verifyFileName(args[2]); String outputAssetDirName = IOHelper.verifyFileName(args[2]);
Path inputAssetDir = server.updatesDir.resolve(inputAssetDirName); var updatesDir = server.config.updatesProvider.getUpdatesDir(inputAssetDirName);
Path outputAssetDir = server.updatesDir.resolve(outputAssetDirName); if(updatesDir == null) {
if (outputAssetDir.equals(inputAssetDir)) server.config.updatesProvider.create(inputAssetDirName);
throw new CommandException("Indexed and unindexed asset dirs can't be same"); }
Path outputAssetDir = Path.of(outputAssetDirName);
// Create new asset dir // Create new asset dir
logger.info("Creating unindexed asset dir: '{}'", outputAssetDirName); logger.info("Creating unindexed asset dir: '{}'", outputAssetDirName);
@ -51,7 +54,8 @@ public void invoke(String... args) throws Exception {
// Read JSON file // Read JSON file
JsonObject objects; JsonObject objects;
logger.info("Reading asset index file: '{}'", indexFileName); logger.info("Reading asset index file: '{}'", indexFileName);
try (BufferedReader reader = IOHelper.newReader(IndexAssetCommand.resolveIndexFile(inputAssetDir, indexFileName))) { Path indexFilePath = IndexAssetCommand.resolveIndexFile(Path.of(""), indexFileName);
try (BufferedReader reader = IOHelper.newReader(server.config.updatesProvider.download(inputAssetDirName, indexFilePath.toString()))) {
objects = JsonParser.parseReader(reader).getAsJsonObject().get("objects").getAsJsonObject(); objects = JsonParser.parseReader(reader).getAsJsonObject().get("objects").getAsJsonObject();
} }
@ -63,12 +67,12 @@ public void invoke(String... args) throws Exception {
// Copy hashed file to target // Copy hashed file to target
String hash = member.getValue().getAsJsonObject().get("hash").getAsString(); String hash = member.getValue().getAsJsonObject().get("hash").getAsString();
Path source = IndexAssetCommand.resolveObjectFile(inputAssetDir, hash); Path source = IndexAssetCommand.resolveObjectFile(Path.of(""), hash);
IOHelper.copy(source, outputAssetDir.resolve(name)); server.config.updatesProvider.download(inputAssetDirName, Map.of(source.toString(), outputAssetDir.resolve(name)));
} }
// Finished // Finished
server.syncUpdatesDir(Collections.singleton(outputAssetDirName)); server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
logger.info("Asset successfully unindexed: '{}'", inputAssetDirName); logger.info("Asset successfully unindexed: '{}'", outputAssetDir.toAbsolutePath().toString());
} }
} }

View file

@ -48,17 +48,7 @@ public void invoke(String... args) throws Exception {
profile.getServers().getFirst().name = args[1]; profile.getServers().getFirst().name = args[1];
} }
logger.info("Copy {} to {}", profile.getDir(), args[1]); logger.info("Copy {} to {}", profile.getDir(), args[1]);
var src = server.updatesDir.resolve(profile.getDir()); server.config.updatesProvider.copy(profile.getDir(), args[1]);
var dest = server.updatesDir.resolve(args[1]);
try (Stream<Path> stream = Files.walk(src)) {
stream.forEach(source -> {
try {
IOHelper.copy(source, dest.resolve(src.relativize(source)));
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
builder.setDir(args[1]); builder.setDir(args[1]);
profile = builder.createClientProfile(); profile = builder.createClientProfile();
server.config.profileProvider.addProfile(profile); server.config.profileProvider.addProfile(profile);

View file

@ -7,6 +7,8 @@
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.helper.MakeProfileHelper; import pro.gravit.launchserver.helper.MakeProfileHelper;
import java.nio.file.Path;
public class MakeProfileCommand extends Command { public class MakeProfileCommand extends Command {
private transient final Logger logger = LogManager.getLogger(); private transient final Logger logger = LogManager.getLogger();
@ -28,7 +30,7 @@ public String getUsageDescription() {
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
verifyArgs(args, 3); verifyArgs(args, 3);
ClientProfile.Version version = parseClientVersion(args[1]); ClientProfile.Version version = parseClientVersion(args[1]);
MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(server.updatesDir.resolve(args[2]), version); MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(Path.of(args[2]), version);
for (MakeProfileHelper.MakeProfileOption option : options) { for (MakeProfileHelper.MakeProfileOption option : options) {
logger.info("Detected option {}", option); logger.info("Detected option {}", option);
} }

View file

@ -2,13 +2,13 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.launcher.base.modules.events.InitPhase; import pro.gravit.launcher.base.modules.events.InitPhase;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class LaunchServerCoreModule extends LauncherModule { public class LaunchServerCoreModule extends LauncherModule {
public LaunchServerCoreModule() { public LaunchServerCoreModule() {
super(new LauncherModuleInfo("LaunchServerCore", Version.getVersion())); super(new LauncherModuleInfoBuilder().setName("LaunchServerCore").setVersion(Version.getVersion()).createLauncherModuleInfo());
} }
@Override @Override

View file

@ -16,7 +16,7 @@ public abstract class LauncherModule {
private LauncherTrustManager.CheckClassResult checkResult; private LauncherTrustManager.CheckClassResult checkResult;
protected LauncherModule() { protected LauncherModule() {
moduleInfo = new LauncherModuleInfo("UnknownModule"); moduleInfo = new LauncherModuleInfoBuilder().setName("UnknownModule").createLauncherModuleInfo();
} }
protected LauncherModule(LauncherModuleInfo info) { protected LauncherModule(LauncherModuleInfo info) {

View file

@ -0,0 +1,40 @@
package pro.gravit.launcher.base.modules;
import pro.gravit.utils.Version;
public class LauncherModuleInfoBuilder {
private String name;
private Version version;
private String[] dependencies = new String[0];
private int priority;
private String[] providers = new String[0];
public LauncherModuleInfoBuilder setName(String name) {
this.name = name;
return this;
}
public LauncherModuleInfoBuilder setVersion(Version version) {
this.version = version;
return this;
}
public LauncherModuleInfoBuilder setDependencies(String[] dependencies) {
this.dependencies = dependencies;
return this;
}
public LauncherModuleInfoBuilder setPriority(int priority) {
this.priority = priority;
return this;
}
public LauncherModuleInfoBuilder setProviders(String[] providers) {
this.providers = providers;
return this;
}
public LauncherModuleInfo createLauncherModuleInfo() {
return new LauncherModuleInfo(name, version, priority, dependencies, providers);
}
}

View file

@ -0,0 +1,59 @@
package pro.gravit.launcher.base.modules;
import pro.gravit.utils.Version;
import java.util.function.Consumer;
public class SimpleModule extends LauncherModule {
protected Consumer<SimpleModuleAccessor> consumer;
public SimpleModule(LauncherModuleInfo info, Consumer<SimpleModuleAccessor> consumer) {
super(info);
this.consumer = consumer;
}
@Override
public void init(LauncherInitContext initContext) {
consumer.accept(new SimpleModuleAccessor(initContext));
}
public static SimpleModule of(String name, Version version, Consumer<SimpleModuleAccessor> consumer) {
return new SimpleModule(new LauncherModuleInfoBuilder()
.setName(name)
.setVersion(version)
.createLauncherModuleInfo(), consumer);
}
public class SimpleModuleAccessor {
private final LauncherInitContext context;
public SimpleModuleAccessor(LauncherInitContext context) {
this.context = context;
}
public final <T extends LauncherModule> T requireModule(Class<? extends T> clazz, Version minVersion) {
return SimpleModule.this.requireModule(clazz, minVersion);
}
public final void requireModule(String name, Version minVersion) {
SimpleModule.this.requireModule(name, minVersion);
}
public final LauncherModulesContext getModulesContext() {
return SimpleModule.this.getContext();
}
public LauncherInitContext getContext() {
return context;
}
public <T extends Event> boolean registerEvent(EventHandler<T> handle, Class<T> tClass) {
return SimpleModule.this.registerEvent(handle, tClass);
}
public final <T extends Event> void callEvent(T event) {
SimpleModule.this.callEvent(event);
}
}
}

View file

@ -2,14 +2,12 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class Cyclic2DependModule extends LauncherModule { public class Cyclic2DependModule extends LauncherModule {
public Cyclic2DependModule() { public Cyclic2DependModule() {
super(new LauncherModuleInfo("cyclic2", super(new LauncherModuleInfoBuilder().setName("cyclic2").setVersion(new Version(1, 0, 0)).setPriority(2).setDependencies(new String[]{"cyclic1"}).createLauncherModuleInfo());
new Version(1, 0, 0),
2, new String[]{"cyclic1"}));
} }
@Override @Override

View file

@ -2,14 +2,12 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class CyclicDependModule extends LauncherModule { public class CyclicDependModule extends LauncherModule {
public CyclicDependModule() { public CyclicDependModule() {
super(new LauncherModuleInfo("cyclic1", super(new LauncherModuleInfoBuilder().setName("cyclic1").setVersion(new Version(1, 0, 0)).setPriority(2).setDependencies(new String[]{"cyclic2"}).createLauncherModuleInfo());
new Version(1, 0, 0),
2, new String[]{"cyclic2"}));
} }
@Override @Override

View file

@ -3,14 +3,12 @@
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class Depend1Module extends LauncherModule { public class Depend1Module extends LauncherModule {
public Depend1Module() { public Depend1Module() {
super(new LauncherModuleInfo("depend1", new Version(1, 0, 0), super(new LauncherModuleInfoBuilder().setName("depend1").setVersion(new Version(1, 0, 0)).setPriority(0).setDependencies(new String[]{"depend3", "internal", "virtual"}).createLauncherModuleInfo());
0,
new String[]{"depend3", "internal", "virtual"}));
} }
@Override @Override

View file

@ -3,12 +3,12 @@
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class Depend2Module extends LauncherModule { public class Depend2Module extends LauncherModule {
public Depend2Module() { public Depend2Module() {
super(new LauncherModuleInfo("depend2")); super(new LauncherModuleInfoBuilder().setName("depend2").createLauncherModuleInfo());
} }
@Override @Override

View file

@ -2,11 +2,11 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
public class Depend3Module extends LauncherModule { public class Depend3Module extends LauncherModule {
public Depend3Module() { public Depend3Module() {
super(new LauncherModuleInfo("depend3")); super(new LauncherModuleInfoBuilder().setName("depend3").createLauncherModuleInfo());
} }
@Override @Override

View file

@ -2,11 +2,11 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
public class InternalModule extends LauncherModule { public class InternalModule extends LauncherModule {
public InternalModule() { public InternalModule() {
super(new LauncherModuleInfo("internal")); super(new LauncherModuleInfoBuilder().setName("internal").createLauncherModuleInfo());
} }
@Override @Override

View file

@ -3,15 +3,13 @@
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class MainModule extends LauncherModule { public class MainModule extends LauncherModule {
public MainModule() { public MainModule() {
super(new LauncherModuleInfo("main", super(new LauncherModuleInfoBuilder().setName("main").setVersion(new Version(1, 0, 0)).setPriority(0).setDependencies(new String[]{"depend1", "depend2"}).createLauncherModuleInfo());
new Version(1, 0, 0),
0, new String[]{"depend1", "depend2"}));
} }
@Override @Override

View file

@ -2,13 +2,12 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class ProvidedModule extends LauncherModule implements VirtualInterface { public class ProvidedModule extends LauncherModule implements VirtualInterface {
public ProvidedModule() { public ProvidedModule() {
super(new LauncherModuleInfo("provided", new Version(1, 0, 0), super(new LauncherModuleInfoBuilder().setName("provided").setVersion(new Version(1, 0, 0)).setPriority(0).setDependencies(new String[]{}).setProviders(new String[]{"virtual"}).createLauncherModuleInfo());
0, new String[]{}, new String[]{"virtual"}));
} }
@Override @Override

View file

@ -1,15 +1,15 @@
package pro.gravit.launcher.impl; package pro.gravit.launcher.impl;
import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.launcher.impl.event.CancelEvent; import pro.gravit.launcher.impl.event.CancelEvent;
import pro.gravit.launcher.impl.event.NormalEvent; import pro.gravit.launcher.impl.event.NormalEvent;
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo;
public class TestModule extends LauncherModule { public class TestModule extends LauncherModule {
public TestModule() { public TestModule() {
super(new LauncherModuleInfo("testModule")); super(new LauncherModuleInfoBuilder().setName("testModule").createLauncherModuleInfo());
} }
@Override @Override

View file

@ -2,12 +2,12 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class ClientLauncherCoreModule extends LauncherModule { public class ClientLauncherCoreModule extends LauncherModule {
public ClientLauncherCoreModule() { public ClientLauncherCoreModule() {
super(new LauncherModuleInfo("ClientLauncherCore", Version.getVersion())); super(new LauncherModuleInfoBuilder().setName("ClientLauncherCore").setVersion(Version.getVersion()).createLauncherModuleInfo());
} }
@Override @Override

View file

@ -2,12 +2,12 @@
import pro.gravit.launcher.base.modules.LauncherInitContext; import pro.gravit.launcher.base.modules.LauncherInitContext;
import pro.gravit.launcher.base.modules.LauncherModule; import pro.gravit.launcher.base.modules.LauncherModule;
import pro.gravit.launcher.base.modules.LauncherModuleInfo; import pro.gravit.launcher.base.modules.LauncherModuleInfoBuilder;
import pro.gravit.utils.Version; import pro.gravit.utils.Version;
public class RuntimeLauncherCoreModule extends LauncherModule { public class RuntimeLauncherCoreModule extends LauncherModule {
public RuntimeLauncherCoreModule() { public RuntimeLauncherCoreModule() {
super(new LauncherModuleInfo("ClientLauncherCore", Version.getVersion())); super(new LauncherModuleInfoBuilder().setName("ClientLauncherCore").setVersion(Version.getVersion()).createLauncherModuleInfo());
} }
@Override @Override

View file

@ -95,6 +95,35 @@ public FindRecursiveResult findRecursive(String path) {
return new FindRecursiveResult(current, entry, name); return new FindRecursiveResult(current, entry, name);
} }
public FindRecursiveResult tryFindRecursive(String path) {
StringTokenizer t = new StringTokenizer(path, "/");
HashedDir current = this;
HashedEntry entry = null;
String name = null;
while (t.hasMoreTokens()) {
name = t.nextToken();
HashedEntry e = current.map.get(name);
if (e == null && !t.hasMoreTokens()) {
break;
}
if (e == null) {
return new FindRecursiveResult(current, entry, name);
}
if (e.getType() == Type.DIR) {
if (!t.hasMoreTokens()) {
entry = e;
break;
} else {
current = ((HashedDir) e);
}
} else {
entry = e;
break;
}
}
return new FindRecursiveResult(current, entry, name);
}
public HashedEntry getEntry(String name) { public HashedEntry getEntry(String name) {
return map.get(name); return map.get(name);
} }
@ -295,6 +324,10 @@ public FindRecursiveResult(HashedDir parent, HashedEntry entry, String name) {
this.entry = entry; this.entry = entry;
this.name = name; this.name = name;
} }
public boolean isFound() {
return entry != null;
}
} }
public static final class Diff { public static final class Diff {

@ -1 +1 @@
Subproject commit a18e0b7d7b6aff2b46c13d0290826cdb8e815dbe Subproject commit 38788df61f8efc5453fe9c05017b629648b5fe6f