mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 11:39:11 +03:00
Merge branch 'dev' of github.com:GravitLauncher/Launcher into dev
This commit is contained in:
commit
7cbfe93320
21 changed files with 91 additions and 970 deletions
|
@ -15,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.UUID;
|
||||||
|
|
||||||
public final class DownloadClientCommand extends Command {
|
public final class DownloadClientCommand extends Command {
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ public void invoke(String... args) throws IOException, CommandException {
|
||||||
}
|
}
|
||||||
client.setTitle(dirName);
|
client.setTitle(dirName);
|
||||||
client.setDir(dirName);
|
client.setDir(dirName);
|
||||||
|
client.setUUID(UUID.randomUUID());
|
||||||
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
|
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
|
||||||
dirName, "json"))) {
|
dirName, "json"))) {
|
||||||
Launcher.gsonManager.configGson.toJson(client, writer);
|
Launcher.gsonManager.configGson.toJson(client, writer);
|
||||||
|
|
|
@ -55,7 +55,6 @@ task javadocJar(type: Jar) {
|
||||||
dependencies {
|
dependencies {
|
||||||
pack project(':LauncherAuthlib')
|
pack project(':LauncherAuthlib')
|
||||||
bundle 'com.github.oshi:oshi-core:3.13.0'
|
bundle 'com.github.oshi:oshi-core:3.13.0'
|
||||||
bundle 'org.apache.httpcomponents:httpclient:4.5.10'
|
|
||||||
pack 'io.netty:netty-codec-http:4.1.43.Final'
|
pack 'io.netty:netty-codec-http:4.1.43.Final'
|
||||||
pack 'org.ow2.asm:asm-tree:7.1'
|
pack 'org.ow2.asm:asm-tree:7.1'
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,6 @@ public void start(String... args) throws Throwable {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (UpdateRequest.getController() == null) UpdateRequest.setController(new LauncherUpdateController());
|
|
||||||
Objects.requireNonNull(args, "args");
|
Objects.requireNonNull(args, "args");
|
||||||
if (started.getAndSet(true))
|
if (started.getAndSet(true))
|
||||||
throw new IllegalStateException("Launcher has been already started");
|
throw new IllegalStateException("Launcher has been already started");
|
||||||
|
@ -166,8 +165,6 @@ public void start(String... args) throws Throwable {
|
||||||
LauncherEngine.modulesManager.invokeEvent(new ClientEngineInitPhase(this));
|
LauncherEngine.modulesManager.invokeEvent(new ClientEngineInitPhase(this));
|
||||||
runtimeProvider.preLoad();
|
runtimeProvider.preLoad();
|
||||||
LauncherGuardManager.initGuard(false);
|
LauncherGuardManager.initGuard(false);
|
||||||
FunctionalBridge.getHWID = CommonHelper.newThread("GetHWID Thread", true, FunctionalBridge::getHWID);
|
|
||||||
FunctionalBridge.getHWID.start();
|
|
||||||
LogHelper.debug("Dir: %s", DirBridge.dir);
|
LogHelper.debug("Dir: %s", DirBridge.dir);
|
||||||
runtimeProvider.run(args);
|
runtimeProvider.run(args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,37 +8,10 @@
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class NewLauncherSettings {
|
public class NewLauncherSettings {
|
||||||
@LauncherAPI
|
|
||||||
public String login;
|
|
||||||
@LauncherAPI
|
|
||||||
public String auth;
|
|
||||||
@LauncherAPI
|
|
||||||
public byte[] rsaPassword;
|
|
||||||
@LauncherAPI
|
|
||||||
public int profile;
|
|
||||||
@LauncherAPI
|
|
||||||
public transient Path updatesDir;
|
|
||||||
@LauncherAPI
|
|
||||||
public String updatesDirPath;
|
|
||||||
@LauncherAPI
|
|
||||||
public boolean autoEnter;
|
|
||||||
@LauncherAPI
|
|
||||||
public boolean debug;
|
|
||||||
@LauncherAPI
|
|
||||||
public boolean fullScreen;
|
|
||||||
@LauncherAPI
|
|
||||||
public boolean offline;
|
|
||||||
@LauncherAPI
|
|
||||||
public int ram;
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public byte[] lastDigest;
|
|
||||||
@LauncherAPI
|
|
||||||
public List<ClientProfile> lastProfiles = new LinkedList<>();
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public Map<String, UserSettings> userSettings = new HashMap<>();
|
public Map<String, UserSettings> userSettings = new HashMap<>();
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public boolean featureStore;
|
public List<String> features = new ArrayList<>();
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public String consoleUnlockKey;
|
public String consoleUnlockKey;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import pro.gravit.launcher.hasher.FileNameMatcher;
|
import pro.gravit.launcher.hasher.FileNameMatcher;
|
||||||
import pro.gravit.launcher.hasher.HashedDir;
|
import pro.gravit.launcher.hasher.HashedDir;
|
||||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||||
|
import pro.gravit.launcher.hwid.OshiHWIDProvider;
|
||||||
import pro.gravit.launcher.managers.ClientGsonManager;
|
import pro.gravit.launcher.managers.ClientGsonManager;
|
||||||
import pro.gravit.launcher.managers.ClientHookManager;
|
import pro.gravit.launcher.managers.ClientHookManager;
|
||||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||||
|
@ -48,6 +49,12 @@
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class ClientLauncher {
|
public final class ClientLauncher {
|
||||||
|
|
||||||
|
@LauncherAPI
|
||||||
|
public static int getClientJVMBits() {
|
||||||
|
return LauncherGuardManager.guard.getClientJVMBits();
|
||||||
|
}
|
||||||
|
|
||||||
private static final class ClassPathFileVisitor extends SimpleFileVisitor<Path> {
|
private static final class ClassPathFileVisitor extends SimpleFileVisitor<Path> {
|
||||||
private final Stream.Builder<Path> result;
|
private final Stream.Builder<Path> result;
|
||||||
|
|
||||||
|
@ -327,7 +334,7 @@ public static Process launch(
|
||||||
context.playerProfile = params.pp;
|
context.playerProfile = params.pp;
|
||||||
context.args.add(javaBin.toString());
|
context.args.add(javaBin.toString());
|
||||||
context.args.add(MAGICAL_INTEL_OPTION);
|
context.args.add(MAGICAL_INTEL_OPTION);
|
||||||
if (params.ram > 0 && params.ram <= FunctionalBridge.getJVMTotalMemory()) {
|
if (params.ram > 0) {
|
||||||
context.args.add("-Xms" + params.ram + 'M');
|
context.args.add("-Xms" + params.ram + 'M');
|
||||||
context.args.add("-Xmx" + params.ram + 'M');
|
context.args.add("-Xmx" + params.ram + 'M');
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ public ClientLauncherContext build() throws IOException {
|
||||||
context.args.add(MAGICAL_INTEL_OPTION);
|
context.args.add(MAGICAL_INTEL_OPTION);
|
||||||
context.params = params;
|
context.params = params;
|
||||||
if(paramsWriter != null) paramsWriter.write(context);
|
if(paramsWriter != null) paramsWriter.write(context);
|
||||||
if (params.ram > 0 && params.ram <= FunctionalBridge.getJVMTotalMemory()) {
|
if (params.ram > 0) {
|
||||||
context.args.add("-Xms" + params.ram + 'M');
|
context.args.add("-Xms" + params.ram + 'M');
|
||||||
context.args.add("-Xmx" + params.ram + 'M');
|
context.args.add("-Xmx" + params.ram + 'M');
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,8 @@ public static void setUseLegacyDir(boolean b) {
|
||||||
try {
|
try {
|
||||||
DirBridge.dir = getLauncherDir(projectName);
|
DirBridge.dir = getLauncherDir(projectName);
|
||||||
if (!IOHelper.exists(DirBridge.dir)) Files.createDirectories(DirBridge.dir);
|
if (!IOHelper.exists(DirBridge.dir)) Files.createDirectories(DirBridge.dir);
|
||||||
|
DirBridge.defaultUpdatesDir = DirBridge.dir.resolve("updates");
|
||||||
|
if (!IOHelper.exists(DirBridge.defaultUpdatesDir)) Files.createDirectories(DirBridge.defaultUpdatesDir);
|
||||||
DirBridge.dirStore = getStoreDir(projectName);
|
DirBridge.dirStore = getStoreDir(projectName);
|
||||||
if (!IOHelper.exists(DirBridge.dirStore)) Files.createDirectories(DirBridge.dirStore);
|
if (!IOHelper.exists(DirBridge.dirStore)) Files.createDirectories(DirBridge.dirStore);
|
||||||
DirBridge.dirProjectStore = getProjectStoreDir(projectName);
|
DirBridge.dirProjectStore = getProjectStoreDir(projectName);
|
||||||
|
|
|
@ -1,144 +0,0 @@
|
||||||
package pro.gravit.launcher.client;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.Launcher;
|
|
||||||
import pro.gravit.launcher.LauncherAPI;
|
|
||||||
import pro.gravit.launcher.api.AuthService;
|
|
||||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
|
||||||
import pro.gravit.launcher.guard.LauncherGuardManager;
|
|
||||||
import pro.gravit.launcher.hasher.FileNameMatcher;
|
|
||||||
import pro.gravit.launcher.hasher.HashedDir;
|
|
||||||
import pro.gravit.launcher.hwid.HWID;
|
|
||||||
import pro.gravit.launcher.hwid.OshiHWIDProvider;
|
|
||||||
import pro.gravit.launcher.managers.ConsoleManager;
|
|
||||||
import pro.gravit.launcher.managers.HasherManager;
|
|
||||||
import pro.gravit.launcher.managers.HasherStore;
|
|
||||||
import pro.gravit.launcher.request.Request;
|
|
||||||
import pro.gravit.utils.Version;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public class FunctionalBridge {
|
|
||||||
@LauncherAPI
|
|
||||||
public static final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(0);
|
|
||||||
@LauncherAPI
|
|
||||||
public static OshiHWIDProvider hwidProvider;
|
|
||||||
@LauncherAPI
|
|
||||||
public static final AtomicReference<HWID> hwid = new AtomicReference<>();
|
|
||||||
@LauncherAPI
|
|
||||||
public static Thread getHWID = null;
|
|
||||||
|
|
||||||
private static long cachedMemorySize = -1;
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static HashedDirRunnable offlineUpdateRequest(String dirName, Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest) {
|
|
||||||
return () -> {
|
|
||||||
if (hdir == null) {
|
|
||||||
Request.requestError(java.lang.String.format("Директории '%s' нет в кэше", dirName));
|
|
||||||
}
|
|
||||||
ClientLauncher.verifyHDir(dir, hdir, matcher, digest);
|
|
||||||
return hdir;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static void startTask(Runnable task) {
|
|
||||||
threadPool.execute(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static HWID getHWID() {
|
|
||||||
HWID hhwid = hwid.get();
|
|
||||||
if (hhwid == null) {
|
|
||||||
if (hwidProvider == null) hwidProvider = new OshiHWIDProvider();
|
|
||||||
hwid.set(hwidProvider.getHWID());
|
|
||||||
}
|
|
||||||
return hhwid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static long getTotalMemory() {
|
|
||||||
if (cachedMemorySize > 0) return cachedMemorySize;
|
|
||||||
if (hwidProvider == null) hwidProvider = new OshiHWIDProvider();
|
|
||||||
return (cachedMemorySize = hwidProvider.getTotalMemory() >> 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static int getClientJVMBits() {
|
|
||||||
return LauncherGuardManager.guard.getClientJVMBits();
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static long getJVMTotalMemory() {
|
|
||||||
if (getClientJVMBits() == 32) {
|
|
||||||
return Math.min(getTotalMemory(), 1536);
|
|
||||||
} else {
|
|
||||||
return getTotalMemory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static HasherStore getDefaultHasherStore() {
|
|
||||||
return HasherManager.getDefaultStore();
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static void registerUserSettings(String typename, Class<? extends UserSettings> clazz) {
|
|
||||||
UserSettings.providers.register(typename, clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static void close() throws Exception {
|
|
||||||
threadPool.awaitTermination(2, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static void setAuthParams(AuthRequestEvent event) {
|
|
||||||
if (event.session != 0) {
|
|
||||||
Request.setSession(event.session);
|
|
||||||
}
|
|
||||||
LauncherGuardManager.guard.setProtectToken(event.protectToken);
|
|
||||||
AuthService.permissions = event.permissions;
|
|
||||||
if (event.playerProfile != null) {
|
|
||||||
AuthService.username = event.playerProfile.username;
|
|
||||||
AuthService.uuid = event.playerProfile.uuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface HashedDirRunnable {
|
|
||||||
HashedDir run() throws Exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static void evalCommand(String cmd) {
|
|
||||||
ConsoleManager.handler.eval(cmd, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static void addPlainOutput(LogHelper.Output output) {
|
|
||||||
LogHelper.addOutput(output, LogHelper.OutputTypes.PLAIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static String getLauncherVersion() {
|
|
||||||
return String.format("GravitLauncher v%d.%d.%d build %d",
|
|
||||||
Version.MAJOR,
|
|
||||||
Version.MINOR,
|
|
||||||
Version.PATCH,
|
|
||||||
Version.BUILD
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public static byte[] encryptPassword(String string) throws Exception {
|
|
||||||
byte[] encode = IOHelper.encode(string);
|
|
||||||
return SecurityHelper.encrypt(Launcher.getConfig().passwordEncryptKey, encode);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
package pro.gravit.launcher.client;
|
package pro.gravit.launcher.client;
|
||||||
|
|
||||||
import pro.gravit.launcher.NewLauncherSettings;
|
import pro.gravit.launcher.NewLauncherSettings;
|
||||||
import pro.gravit.launcher.downloader.ListDownloader;
|
|
||||||
import pro.gravit.launcher.events.request.UpdateRequestEvent;
|
import pro.gravit.launcher.events.request.UpdateRequestEvent;
|
||||||
import pro.gravit.launcher.hasher.HashedDir;
|
import pro.gravit.launcher.hasher.HashedDir;
|
||||||
import pro.gravit.launcher.hasher.HashedEntry;
|
import pro.gravit.launcher.hasher.HashedEntry;
|
||||||
|
@ -17,77 +16,66 @@
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
@Deprecated
|
||||||
|
public class LauncherUpdateController {
|
||||||
|
|
||||||
public class LauncherUpdateController implements UpdateRequest.UpdateController {
|
|
||||||
@Override
|
|
||||||
public void preUpdate(UpdateRequest request, UpdateRequestEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preDiff(UpdateRequest request, UpdateRequestEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postDiff(UpdateRequest request, UpdateRequestEvent e, HashedDir.Diff diff) throws IOException {
|
public void postDiff(UpdateRequest request, UpdateRequestEvent e, HashedDir.Diff diff) throws IOException {
|
||||||
|
/*
|
||||||
if (e.zip && e.fullDownload) return;
|
if (e.zip && e.fullDownload) return;
|
||||||
if (SettingsManager.settings.featureStore) {
|
LogHelper.info("Enabled HStore feature. Find");
|
||||||
LogHelper.info("Enabled HStore feature. Find");
|
AtomicReference<NewLauncherSettings.HashedStoreEntry> lastEn = new AtomicReference<>(null);
|
||||||
AtomicReference<NewLauncherSettings.HashedStoreEntry> lastEn = new AtomicReference<>(null);
|
//ArrayList<String> removed = new ArrayList<>();
|
||||||
//ArrayList<String> removed = new ArrayList<>();
|
diff.mismatch.walk(File.separator, (path, name, entry) -> {
|
||||||
diff.mismatch.walk(File.separator, (path, name, entry) -> {
|
if (entry.getType() == HashedEntry.Type.DIR) {
|
||||||
if (entry.getType() == HashedEntry.Type.DIR) {
|
Files.createDirectories(request.getDir().resolve(path));
|
||||||
Files.createDirectories(request.getDir().resolve(path));
|
|
||||||
return HashedDir.WalkAction.CONTINUE;
|
|
||||||
}
|
|
||||||
HashedFile file = (HashedFile) entry;
|
|
||||||
//Первый экспериментальный способ - честно обходим все возможные Store
|
|
||||||
Path ret = null;
|
|
||||||
if (lastEn.get() == null) {
|
|
||||||
for (NewLauncherSettings.HashedStoreEntry en : SettingsManager.settings.lastHDirs) {
|
|
||||||
ret = tryFind(en, file);
|
|
||||||
if (ret != null) {
|
|
||||||
lastEn.set(en);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret = tryFind(lastEn.get(), file);
|
|
||||||
}
|
|
||||||
if (ret == null) {
|
|
||||||
for (NewLauncherSettings.HashedStoreEntry en : SettingsManager.settings.lastHDirs) {
|
|
||||||
ret = tryFind(en, file);
|
|
||||||
if (ret != null) {
|
|
||||||
lastEn.set(en);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ret != null) {
|
|
||||||
//Еще раз проверим корректность хеша
|
|
||||||
//Возможно эта проверка избыточна
|
|
||||||
//if(file.isSame(ret, true))
|
|
||||||
{
|
|
||||||
Path source = request.getDir().resolve(path);
|
|
||||||
if (LogHelper.isDebugEnabled()) {
|
|
||||||
LogHelper.debug("Copy file %s to %s", ret.toAbsolutePath().toString(), source.toAbsolutePath().toString());
|
|
||||||
}
|
|
||||||
//Let's go!
|
|
||||||
Files.deleteIfExists(source);
|
|
||||||
Files.copy(ret, source);
|
|
||||||
try (InputStream input = IOHelper.newInput(ret)) {
|
|
||||||
IOHelper.transfer(input, source);
|
|
||||||
}
|
|
||||||
entry.flag = true;
|
|
||||||
//removed.add(path.replace('\\', '/'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return HashedDir.WalkAction.CONTINUE;
|
return HashedDir.WalkAction.CONTINUE;
|
||||||
});
|
}
|
||||||
}
|
HashedFile file = (HashedFile) entry;
|
||||||
|
//Первый экспериментальный способ - честно обходим все возможные Store
|
||||||
|
Path ret = null;
|
||||||
|
if (lastEn.get() == null) {
|
||||||
|
for (NewLauncherSettings.HashedStoreEntry en : SettingsManager.settings.lastHDirs) {
|
||||||
|
ret = tryFind(en, file);
|
||||||
|
if (ret != null) {
|
||||||
|
lastEn.set(en);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = tryFind(lastEn.get(), file);
|
||||||
|
}
|
||||||
|
if (ret == null) {
|
||||||
|
for (NewLauncherSettings.HashedStoreEntry en : SettingsManager.settings.lastHDirs) {
|
||||||
|
ret = tryFind(en, file);
|
||||||
|
if (ret != null) {
|
||||||
|
lastEn.set(en);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret != null) {
|
||||||
|
//Еще раз проверим корректность хеша
|
||||||
|
//Возможно эта проверка избыточна
|
||||||
|
//if(file.isSame(ret, true))
|
||||||
|
{
|
||||||
|
Path source = request.getDir().resolve(path);
|
||||||
|
if (LogHelper.isDebugEnabled()) {
|
||||||
|
LogHelper.debug("Copy file %s to %s", ret.toAbsolutePath().toString(), source.toAbsolutePath().toString());
|
||||||
|
}
|
||||||
|
//Let's go!
|
||||||
|
Files.deleteIfExists(source);
|
||||||
|
Files.copy(ret, source);
|
||||||
|
try (InputStream input = IOHelper.newInput(ret)) {
|
||||||
|
IOHelper.transfer(input, source);
|
||||||
|
}
|
||||||
|
entry.flag = true;
|
||||||
|
//removed.add(path.replace('\\', '/'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HashedDir.WalkAction.CONTINUE;
|
||||||
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path tryFind(NewLauncherSettings.HashedStoreEntry en, HashedFile file) throws IOException {
|
public Path tryFind(NewLauncherSettings.HashedStoreEntry en, HashedFile file) throws IOException {
|
||||||
|
@ -116,19 +104,4 @@ public Path tryFind(NewLauncherSettings.HashedStoreEntry en, HashedFile file) th
|
||||||
});
|
});
|
||||||
return ret.get();
|
return ret.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preDownload(UpdateRequest request, UpdateRequestEvent e, List<ListDownloader.DownloadTask> adds) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postDownload(UpdateRequest request, UpdateRequestEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postUpdate(UpdateRequest request, UpdateRequestEvent e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
package pro.gravit.launcher.console;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.managers.SettingsManager;
|
|
||||||
import pro.gravit.utils.command.Command;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
public class FeatureCommand extends Command {
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[feature] [true/false]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Enable or disable feature";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 2);
|
|
||||||
boolean enabled = Boolean.parseBoolean(args[1]);
|
|
||||||
switch (args[0]) {
|
|
||||||
case "store": {
|
|
||||||
SettingsManager.settings.featureStore = enabled;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
LogHelper.info("Features: [store]");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LogHelper.info("Feature %s %s", args[0], enabled ? "enabled" : "disabled");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package pro.gravit.launcher.console.store;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.NewLauncherSettings;
|
|
||||||
import pro.gravit.launcher.managers.SettingsManager;
|
|
||||||
import pro.gravit.utils.command.Command;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
public class CopyStoreDirCommand extends Command {
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[index] [overwrite(true/false)]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Copy dir in GravitLauncherStore";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 2);
|
|
||||||
int ind = 1;
|
|
||||||
int index = Integer.parseInt(args[0]);
|
|
||||||
boolean overwrite = Boolean.parseBoolean(args[1]);
|
|
||||||
for (NewLauncherSettings.HashedStoreEntry e : SettingsManager.settings.lastHDirs) {
|
|
||||||
if (ind == index) {
|
|
||||||
LogHelper.info("Copy [%d] FullPath: %s name: %s", ind, e.fullPath, e.name);
|
|
||||||
Path path = Paths.get(e.fullPath);
|
|
||||||
if (!Files.isDirectory(path)) {
|
|
||||||
LogHelper.error("Directory %s not found", path.toAbsolutePath().toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Path target = Paths.get(SettingsManager.settings.updatesDirPath).resolve(e.name);
|
|
||||||
if (Files.exists(target) && !overwrite) {
|
|
||||||
LogHelper.error("Directory %s found, flag overwrite not found", target.toAbsolutePath().toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Files.copy(path, target);
|
|
||||||
}
|
|
||||||
ind++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package pro.gravit.launcher.console.store;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.NewLauncherSettings;
|
|
||||||
import pro.gravit.launcher.managers.SettingsManager;
|
|
||||||
import pro.gravit.utils.command.Command;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
public class LinkStoreDirCommand extends Command {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[index]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Create symlink to GravitLauncherStore directory";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 1);
|
|
||||||
int ind = 1;
|
|
||||||
int index = Integer.parseInt(args[0]);
|
|
||||||
for (NewLauncherSettings.HashedStoreEntry e : SettingsManager.settings.lastHDirs) {
|
|
||||||
if (ind == index) {
|
|
||||||
LogHelper.info("Copy [%d] FullPath: %s name: %s", ind, e.fullPath, e.name);
|
|
||||||
Path path = Paths.get(e.fullPath);
|
|
||||||
if (!Files.isDirectory(path)) {
|
|
||||||
LogHelper.error("Directory %s not found", path.toAbsolutePath().toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Path target = Paths.get(SettingsManager.settings.updatesDirPath).resolve(e.name);
|
|
||||||
if (Files.exists(target)) {
|
|
||||||
LogHelper.error("Directory %s already exists", target.toAbsolutePath().toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Files.createSymbolicLink(path, target);
|
|
||||||
}
|
|
||||||
ind++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package pro.gravit.launcher.console.store;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.NewLauncherSettings;
|
|
||||||
import pro.gravit.launcher.managers.SettingsManager;
|
|
||||||
import pro.gravit.utils.command.Command;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
public class StoreListCommand extends Command {
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "List GravitLauncherStore";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) {
|
|
||||||
int ind = 1;
|
|
||||||
for (NewLauncherSettings.HashedStoreEntry e : SettingsManager.settings.lastHDirs) {
|
|
||||||
LogHelper.info("[%d] FullPath: %s name: %s", ind, e.fullPath, e.name);
|
|
||||||
ind++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,9 @@
|
||||||
package pro.gravit.launcher.managers;
|
package pro.gravit.launcher.managers;
|
||||||
|
|
||||||
import pro.gravit.launcher.Launcher;
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launcher.console.FeatureCommand;
|
|
||||||
import pro.gravit.launcher.console.UnlockCommand;
|
import pro.gravit.launcher.console.UnlockCommand;
|
||||||
import pro.gravit.launcher.console.admin.ExecCommand;
|
import pro.gravit.launcher.console.admin.ExecCommand;
|
||||||
import pro.gravit.launcher.console.admin.LogListenerCommand;
|
import pro.gravit.launcher.console.admin.LogListenerCommand;
|
||||||
import pro.gravit.launcher.console.store.CopyStoreDirCommand;
|
|
||||||
import pro.gravit.launcher.console.store.LinkStoreDirCommand;
|
|
||||||
import pro.gravit.launcher.console.store.StoreListCommand;
|
|
||||||
import pro.gravit.utils.command.BaseCommandCategory;
|
import pro.gravit.utils.command.BaseCommandCategory;
|
||||||
import pro.gravit.utils.command.CommandHandler;
|
import pro.gravit.utils.command.CommandHandler;
|
||||||
import pro.gravit.utils.command.JLineCommandHandler;
|
import pro.gravit.utils.command.JLineCommandHandler;
|
||||||
|
@ -57,16 +53,10 @@ public static boolean checkUnlockKey(String key) {
|
||||||
|
|
||||||
public static void unlock() {
|
public static void unlock() {
|
||||||
handler.registerCommand("debug", new DebugCommand());
|
handler.registerCommand("debug", new DebugCommand());
|
||||||
handler.registerCommand("feature", new FeatureCommand());
|
|
||||||
BaseCommandCategory admin = new BaseCommandCategory();
|
BaseCommandCategory admin = new BaseCommandCategory();
|
||||||
admin.registerCommand("exec", new ExecCommand());
|
admin.registerCommand("exec", new ExecCommand());
|
||||||
admin.registerCommand("logListen", new LogListenerCommand());
|
admin.registerCommand("logListen", new LogListenerCommand());
|
||||||
handler.registerCategory(new CommandHandler.Category(admin, "admin", "Server admin commands"));
|
handler.registerCategory(new CommandHandler.Category(admin, "admin", "Server admin commands"));
|
||||||
BaseCommandCategory store = new BaseCommandCategory();
|
|
||||||
store.registerCommand("storeList", new StoreListCommand());
|
|
||||||
store.registerCommand("copyStoreDir", new CopyStoreDirCommand());
|
|
||||||
store.registerCommand("linkStoreDir", new LinkStoreDirCommand());
|
|
||||||
handler.registerCategory(new CommandHandler.Category(admin, "store", "Store admin commands"));
|
|
||||||
isConsoleUnlock = true;
|
isConsoleUnlock = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,6 @@ public SettingsManager() {
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
@Override
|
@Override
|
||||||
public NewLauncherSettings getConfig() {
|
public NewLauncherSettings getConfig() {
|
||||||
if (settings.updatesDir != null)
|
|
||||||
settings.updatesDirPath = settings.updatesDir.toString();
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +55,6 @@ public NewLauncherSettings getDefaultConfig() {
|
||||||
@Override
|
@Override
|
||||||
public void setConfig(NewLauncherSettings config) {
|
public void setConfig(NewLauncherSettings config) {
|
||||||
settings = config;
|
settings = config;
|
||||||
if (settings.updatesDirPath != null)
|
|
||||||
settings.updatesDir = Paths.get(settings.updatesDirPath);
|
|
||||||
if (settings.consoleUnlockKey != null && !ConsoleManager.isConsoleUnlock) {
|
if (settings.consoleUnlockKey != null && !ConsoleManager.isConsoleUnlock) {
|
||||||
if (ConsoleManager.checkUnlockKey(settings.consoleUnlockKey)) {
|
if (ConsoleManager.checkUnlockKey(settings.consoleUnlockKey)) {
|
||||||
ConsoleManager.unlock();
|
ConsoleManager.unlock();
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':LauncherCore')
|
compile project(':LauncherCore')
|
||||||
compileOnly 'org.apache.httpcomponents:httpclient:4.5.10'
|
|
||||||
compileOnly 'io.netty:netty-codec-http:4.1.43.Final'
|
compileOnly 'io.netty:netty-codec-http:4.1.43.Final'
|
||||||
testCompile 'org.junit.jupiter:junit-jupiter:5.4.1'
|
testCompile 'org.junit.jupiter:junit-jupiter:5.4.1'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,252 +0,0 @@
|
||||||
package pro.gravit.launcher.downloader;
|
|
||||||
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.apache.http.client.ResponseHandler;
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClients;
|
|
||||||
import org.apache.http.impl.client.LaxRedirectStrategy;
|
|
||||||
import pro.gravit.utils.helper.CommonHelper;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
import pro.gravit.utils.helper.VerifyHelper;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
|
|
||||||
public class ListDownloader {
|
|
||||||
private static final AtomicInteger COUNTER_THR = new AtomicInteger(0);
|
|
||||||
private static final ThreadFactory FACTORY = r -> CommonHelper.newThread("Downloader Thread #" + COUNTER_THR.incrementAndGet(), true, r);
|
|
||||||
|
|
||||||
private static ExecutorService newExecutor() {
|
|
||||||
return new ThreadPoolExecutor(0, VerifyHelper.verifyInt(Integer.parseInt(System.getProperty("launcher.downloadThreads", "3")), VerifyHelper.POSITIVE, "Thread max count must be positive."), 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), FACTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface DownloadCallback {
|
|
||||||
void stateChanged(String filename, long downloadedSize, long size);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface DownloadTotalCallback {
|
|
||||||
void addTotal(long size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DownloadTask {
|
|
||||||
public final String apply;
|
|
||||||
public long size;
|
|
||||||
public final String urlApply;
|
|
||||||
|
|
||||||
public DownloadTask(String apply, long size) {
|
|
||||||
this.apply = apply;
|
|
||||||
urlApply = apply;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DownloadTask(String urlApply, String apply, long size) {
|
|
||||||
this.apply = apply;
|
|
||||||
this.urlApply = urlApply;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void download(String base, List<DownloadTask> applies, Path dstDirFile, DownloadCallback callback, DownloadTotalCallback totalCallback) throws IOException, URISyntaxException {
|
|
||||||
try (CloseableHttpClient httpclient = HttpClients.custom().setUserAgent(IOHelper.USER_AGENT)
|
|
||||||
.setRedirectStrategy(new LaxRedirectStrategy())
|
|
||||||
.build()) {
|
|
||||||
applies.sort(Comparator.comparingLong(a -> a.size));
|
|
||||||
List<Callable<Void>> toExec = new ArrayList<>();
|
|
||||||
URI baseUri = new URI(base);
|
|
||||||
String scheme = baseUri.getScheme();
|
|
||||||
String host = baseUri.getHost();
|
|
||||||
int port = baseUri.getPort();
|
|
||||||
if (port != -1)
|
|
||||||
host = host + ":" + port;
|
|
||||||
String path = baseUri.getPath();
|
|
||||||
List<IOException> excs = new CopyOnWriteArrayList<>();
|
|
||||||
for (DownloadTask apply : applies) {
|
|
||||||
URI u = new URI(scheme, host, path + apply.urlApply, "", "");
|
|
||||||
callback.stateChanged(apply.apply, 0L, apply.size);
|
|
||||||
Path targetPath = dstDirFile.resolve(apply.apply);
|
|
||||||
toExec.add(() -> {
|
|
||||||
if (LogHelper.isDebugEnabled())
|
|
||||||
LogHelper.debug("Download URL: %s to file %s dir: %s", u.toString(), targetPath.toAbsolutePath().toString(), dstDirFile.toAbsolutePath().toString());
|
|
||||||
try {
|
|
||||||
httpclient.execute(new HttpGet(u), new FileDownloadResponseHandler(targetPath, apply, callback, totalCallback, false));
|
|
||||||
} catch (IOException e) {
|
|
||||||
excs.add(e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ExecutorService e = newExecutor();
|
|
||||||
e.invokeAll(toExec);
|
|
||||||
e.shutdown();
|
|
||||||
e.awaitTermination(4, TimeUnit.HOURS);
|
|
||||||
} catch (InterruptedException t) {
|
|
||||||
LogHelper.error(t);
|
|
||||||
}
|
|
||||||
if (!excs.isEmpty()) {
|
|
||||||
IOException toThrow = excs.remove(0);
|
|
||||||
excs.forEach(toThrow::addSuppressed);
|
|
||||||
throw toThrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void downloadZip(String base, List<DownloadTask> applies, Path dstDirFile, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean fullDownload) throws IOException {
|
|
||||||
/*try (CloseableHttpClient httpclient = HttpClients.custom()
|
|
||||||
.setRedirectStrategy(new LaxRedirectStrategy())
|
|
||||||
.build()) {
|
|
||||||
HttpGet get;
|
|
||||||
URI u = new URL(base).toURI();
|
|
||||||
LogHelper.debug("Download ZIP URL: %s", u.toString());
|
|
||||||
get = new HttpGet(u);
|
|
||||||
httpclient.execute(get, new FileDownloadResponseHandler(dstDirFile, callback, totalCallback, true));
|
|
||||||
}*/
|
|
||||||
try (ZipInputStream input = IOHelper.newZipInput(new URL(base))) {
|
|
||||||
for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
|
|
||||||
if (entry.isDirectory())
|
|
||||||
continue; // Skip directories
|
|
||||||
// Unpack entry
|
|
||||||
String name = entry.getName();
|
|
||||||
callback.stateChanged(name, 0L, entry.getSize());
|
|
||||||
LogHelper.subInfo("Downloading file: '%s'", name);
|
|
||||||
if (fullDownload || applies.stream().anyMatch((t) -> t.apply.equals(name))) {
|
|
||||||
Path fileName = IOHelper.toPath(name);
|
|
||||||
transfer(input, dstDirFile.resolve(fileName), fileName.toString(), entry.getSize(), callback, totalCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void downloadOne(String url, Path target) throws IOException, URISyntaxException {
|
|
||||||
try (CloseableHttpClient httpclient = HttpClients.custom()
|
|
||||||
.setRedirectStrategy(new LaxRedirectStrategy())
|
|
||||||
.build()) {
|
|
||||||
|
|
||||||
HttpGet get;
|
|
||||||
URI u = new URL(url).toURI();
|
|
||||||
if (LogHelper.isDebugEnabled()) {
|
|
||||||
LogHelper.debug("Download URL: %s", u.toString());
|
|
||||||
}
|
|
||||||
get = new HttpGet(u);
|
|
||||||
httpclient.execute(get, new FileDownloadResponseHandler(target.toAbsolutePath()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class FileDownloadResponseHandler implements ResponseHandler<Path> {
|
|
||||||
private final Path target;
|
|
||||||
private final DownloadTask task;
|
|
||||||
private final DownloadCallback callback;
|
|
||||||
private final DownloadTotalCallback totalCallback;
|
|
||||||
private final boolean zip;
|
|
||||||
|
|
||||||
public FileDownloadResponseHandler(Path target) {
|
|
||||||
this.target = target;
|
|
||||||
this.task = null;
|
|
||||||
this.zip = false;
|
|
||||||
callback = null;
|
|
||||||
totalCallback = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileDownloadResponseHandler(Path target, DownloadTask task, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean zip) {
|
|
||||||
this.target = target;
|
|
||||||
this.task = task;
|
|
||||||
this.callback = callback;
|
|
||||||
this.totalCallback = totalCallback;
|
|
||||||
this.zip = zip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileDownloadResponseHandler(Path target, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean zip) {
|
|
||||||
this.target = target;
|
|
||||||
this.task = null;
|
|
||||||
this.callback = callback;
|
|
||||||
this.totalCallback = totalCallback;
|
|
||||||
this.zip = zip;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Path handleResponse(HttpResponse response) throws IOException {
|
|
||||||
InputStream source = response.getEntity().getContent();
|
|
||||||
int returnCode = response.getStatusLine().getStatusCode();
|
|
||||||
if (returnCode != 200) {
|
|
||||||
throw new IllegalStateException(String.format("Request download file %s return code %d", target.toString(), returnCode));
|
|
||||||
}
|
|
||||||
long contentLength = response.getEntity().getContentLength();
|
|
||||||
if (task != null && contentLength != task.size) {
|
|
||||||
if (task.size > 0)
|
|
||||||
LogHelper.warning("Missing content length: expected %d | found %d", task.size, contentLength);
|
|
||||||
else task.size = contentLength;
|
|
||||||
}
|
|
||||||
if (zip) {
|
|
||||||
try (ZipInputStream input = IOHelper.newZipInput(source)) {
|
|
||||||
ZipEntry entry = input.getNextEntry();
|
|
||||||
while (entry != null) {
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
entry = input.getNextEntry();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
long size = entry.getSize();
|
|
||||||
String filename = entry.getName();
|
|
||||||
Path target = this.target.resolve(filename);
|
|
||||||
if (callback != null) {
|
|
||||||
callback.stateChanged(entry.getName(), 0, entry.getSize());
|
|
||||||
}
|
|
||||||
if (LogHelper.isDevEnabled()) {
|
|
||||||
LogHelper.dev("Resolved filename %s to %s", filename, target.toAbsolutePath().toString());
|
|
||||||
}
|
|
||||||
transfer(source, target, filename, size, callback, totalCallback);
|
|
||||||
entry = input.getNextEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (callback != null && task != null) {
|
|
||||||
callback.stateChanged(task.apply, 0, task.size);
|
|
||||||
transfer(source, this.target, task.apply, task.size, callback, totalCallback);
|
|
||||||
} else
|
|
||||||
IOHelper.transfer(source, this.target);
|
|
||||||
return this.target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void transfer(InputStream input, Path file, String filename, long size, DownloadCallback callback, DownloadTotalCallback totalCallback) throws IOException {
|
|
||||||
try (OutputStream fileOutput = IOHelper.newOutput(file)) {
|
|
||||||
long downloaded = 0L;
|
|
||||||
|
|
||||||
// Download with digest update
|
|
||||||
byte[] bytes = IOHelper.newBuffer();
|
|
||||||
while (downloaded < size) {
|
|
||||||
int remaining = (int) Math.min(size - downloaded, bytes.length);
|
|
||||||
int length = input.read(bytes, 0, remaining);
|
|
||||||
if (length < 0)
|
|
||||||
throw new EOFException(String.format("%d bytes remaining", size - downloaded));
|
|
||||||
|
|
||||||
// Update file
|
|
||||||
fileOutput.write(bytes, 0, length);
|
|
||||||
|
|
||||||
// Update state
|
|
||||||
downloaded += length;
|
|
||||||
//totalDownloaded += length;
|
|
||||||
totalCallback.addTotal(length);
|
|
||||||
callback.stateChanged(filename, downloaded, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -86,6 +86,8 @@ public String toString() {
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
private int sortIndex;
|
private int sortIndex;
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
|
private UUID uuid;
|
||||||
|
@LauncherAPI
|
||||||
private String title;
|
private String title;
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
private String info;
|
private String info;
|
||||||
|
@ -384,11 +386,19 @@ public void setVersion(Version version) {
|
||||||
this.version = version.name;
|
this.version = version.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUUID(UUID uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getUUID() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public void verify() {
|
public void verify() {
|
||||||
// Version
|
// Version
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import pro.gravit.launcher.Launcher;
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launcher.LauncherAPI;
|
import pro.gravit.launcher.LauncherAPI;
|
||||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.downloader.ListDownloader;
|
|
||||||
import pro.gravit.launcher.events.request.LauncherRequestEvent;
|
import pro.gravit.launcher.events.request.LauncherRequestEvent;
|
||||||
import pro.gravit.launcher.request.Request;
|
import pro.gravit.launcher.request.Request;
|
||||||
import pro.gravit.launcher.request.websockets.StandartClientWebSocketService;
|
import pro.gravit.launcher.request.websockets.StandartClientWebSocketService;
|
||||||
|
@ -15,6 +14,8 @@
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -60,9 +61,13 @@ public static void update(LauncherRequestEvent result) throws IOException {
|
||||||
IOHelper.transfer(BINARY_PATH, stream);
|
IOHelper.transfer(BINARY_PATH, stream);
|
||||||
}*/
|
}*/
|
||||||
try {
|
try {
|
||||||
ListDownloader downloader = new ListDownloader();
|
|
||||||
Files.deleteIfExists(C_BINARY_PATH);
|
Files.deleteIfExists(C_BINARY_PATH);
|
||||||
downloader.downloadOne(result.url, C_BINARY_PATH);
|
URL url = new URL(result.url);
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
try(InputStream in = connection.getInputStream())
|
||||||
|
{
|
||||||
|
IOHelper.transfer(in, C_BINARY_PATH);
|
||||||
|
}
|
||||||
try (InputStream in = IOHelper.newInput(C_BINARY_PATH)) {
|
try (InputStream in = IOHelper.newInput(C_BINARY_PATH)) {
|
||||||
IOHelper.transfer(in, BINARY_PATH);
|
IOHelper.transfer(in, BINARY_PATH);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,16 @@
|
||||||
package pro.gravit.launcher.request.update;
|
package pro.gravit.launcher.request.update;
|
||||||
|
|
||||||
import pro.gravit.launcher.Launcher;
|
|
||||||
import pro.gravit.launcher.LauncherAPI;
|
|
||||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.downloader.ListDownloader;
|
|
||||||
import pro.gravit.launcher.events.request.UpdateRequestEvent;
|
import pro.gravit.launcher.events.request.UpdateRequestEvent;
|
||||||
import pro.gravit.launcher.hasher.FileNameMatcher;
|
|
||||||
import pro.gravit.launcher.hasher.HashedDir;
|
|
||||||
import pro.gravit.launcher.hasher.HashedEntry;
|
|
||||||
import pro.gravit.launcher.hasher.HashedFile;
|
|
||||||
import pro.gravit.launcher.request.Request;
|
import pro.gravit.launcher.request.Request;
|
||||||
import pro.gravit.launcher.request.update.UpdateRequest.State.Callback;
|
|
||||||
import pro.gravit.launcher.request.websockets.StandartClientWebSocketService;
|
import pro.gravit.launcher.request.websockets.StandartClientWebSocketService;
|
||||||
import pro.gravit.launcher.request.websockets.WebSocketRequest;
|
import pro.gravit.launcher.request.websockets.WebSocketRequest;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public final class UpdateRequest extends Request<UpdateRequestEvent> implements WebSocketRequest {
|
public final class UpdateRequest extends Request<UpdateRequestEvent> implements WebSocketRequest {
|
||||||
public interface UpdateController {
|
|
||||||
void preUpdate(UpdateRequest request, UpdateRequestEvent e);
|
|
||||||
|
|
||||||
void preDiff(UpdateRequest request, UpdateRequestEvent e);
|
public UpdateRequest(String dirName) {
|
||||||
|
this.dirName = dirName;
|
||||||
void postDiff(UpdateRequest request, UpdateRequestEvent e, HashedDir.Diff diff) throws IOException;
|
|
||||||
|
|
||||||
void preDownload(UpdateRequest request, UpdateRequestEvent e, List<ListDownloader.DownloadTask> adds);
|
|
||||||
|
|
||||||
void postDownload(UpdateRequest request, UpdateRequestEvent e);
|
|
||||||
|
|
||||||
void postUpdate(UpdateRequest request, UpdateRequestEvent e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UpdateController controller;
|
|
||||||
|
|
||||||
public static void setController(UpdateController controller) {
|
|
||||||
UpdateRequest.controller = controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UpdateController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,258 +18,15 @@ public String getType() {
|
||||||
return "update";
|
return "update";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class State {
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Callback {
|
|
||||||
@LauncherAPI
|
|
||||||
void call(State state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public final long fileDownloaded;
|
|
||||||
@LauncherAPI
|
|
||||||
public final long fileSize;
|
|
||||||
@LauncherAPI
|
|
||||||
public final long totalDownloaded;
|
|
||||||
@LauncherAPI
|
|
||||||
public final long totalSize;
|
|
||||||
@LauncherAPI
|
|
||||||
public final String filePath;
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public final Duration duration;
|
|
||||||
|
|
||||||
public State(String filePath, long fileDownloaded, long fileSize, long totalDownloaded, long totalSize, Duration duration) {
|
|
||||||
this.filePath = filePath;
|
|
||||||
this.fileDownloaded = fileDownloaded;
|
|
||||||
this.fileSize = fileSize;
|
|
||||||
this.totalDownloaded = totalDownloaded;
|
|
||||||
this.totalSize = totalSize;
|
|
||||||
|
|
||||||
// Also store time of creation
|
|
||||||
this.duration = duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getBps() {
|
|
||||||
long seconds = duration.getSeconds();
|
|
||||||
if (seconds == 0)
|
|
||||||
return -1.0D; // Otherwise will throw /0 exception
|
|
||||||
return totalDownloaded / (double) seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public Duration getEstimatedTime() {
|
|
||||||
double bps = getBps();
|
|
||||||
if (bps <= 0.0D)
|
|
||||||
return null; // Otherwise will throw /0 exception
|
|
||||||
return Duration.ofSeconds((long) (getTotalRemaining() / bps));
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getFileDownloadedKiB() {
|
|
||||||
return fileDownloaded / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getFileDownloadedMiB() {
|
|
||||||
return getFileDownloadedKiB() / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getFileDownloadedPart() {
|
|
||||||
if (fileSize == 0)
|
|
||||||
return 0.0D;
|
|
||||||
return (double) fileDownloaded / fileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public long getFileRemaining() {
|
|
||||||
return fileSize - fileDownloaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getFileRemainingKiB() {
|
|
||||||
return getFileRemaining() / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getFileRemainingMiB() {
|
|
||||||
return getFileRemainingKiB() / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getFileSizeKiB() {
|
|
||||||
return fileSize / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getFileSizeMiB() {
|
|
||||||
return getFileSizeKiB() / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getTotalDownloadedKiB() {
|
|
||||||
return totalDownloaded / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getTotalDownloadedMiB() {
|
|
||||||
return getTotalDownloadedKiB() / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getTotalDownloadedPart() {
|
|
||||||
if (totalSize == 0)
|
|
||||||
return 0.0D;
|
|
||||||
return (double) totalDownloaded / totalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public long getTotalRemaining() {
|
|
||||||
return totalSize - totalDownloaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getTotalRemainingKiB() {
|
|
||||||
return getTotalRemaining() / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getTotalRemainingMiB() {
|
|
||||||
return getTotalRemainingKiB() / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getTotalSizeKiB() {
|
|
||||||
return totalSize / 1024.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public double getTotalSizeMiB() {
|
|
||||||
return getTotalSizeKiB() / 1024.0D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpdateRequestEvent requestDo(StandartClientWebSocketService service) throws Exception {
|
public UpdateRequestEvent requestDo(StandartClientWebSocketService service) throws Exception {
|
||||||
LogHelper.debug("Start update request");
|
LogHelper.debug("Start update request");
|
||||||
UpdateRequestEvent e = (UpdateRequestEvent) service.sendRequest(this);
|
return (UpdateRequestEvent) service.sendRequest(this);
|
||||||
if (controller != null) controller.preUpdate(this, e);
|
|
||||||
LogHelper.debug("Start update");
|
|
||||||
Launcher.profile.pushOptionalFile(e.hdir, !Launcher.profile.isUpdateFastCheck());
|
|
||||||
if (controller != null) controller.preDiff(this, e);
|
|
||||||
HashedDir.Diff diff = e.hdir.diff(localDir, matcher);
|
|
||||||
if (controller != null) controller.postDiff(this, e, diff);
|
|
||||||
final List<ListDownloader.DownloadTask> adds = new ArrayList<>();
|
|
||||||
if (controller != null) controller.preDownload(this, e, adds);
|
|
||||||
diff.mismatch.walk(IOHelper.CROSS_SEPARATOR, (path, name, entry) -> {
|
|
||||||
if (entry.getType().equals(HashedEntry.Type.FILE)) {
|
|
||||||
if (!entry.flag) {
|
|
||||||
HashedFile file = (HashedFile) entry;
|
|
||||||
totalSize += file.size;
|
|
||||||
adds.add(new ListDownloader.DownloadTask(path, file.size));
|
|
||||||
}
|
|
||||||
} else if (entry.getType().equals(HashedEntry.Type.DIR)) {
|
|
||||||
try {
|
|
||||||
Files.createDirectories(dir.resolve(path));
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LogHelper.error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return HashedDir.WalkAction.CONTINUE;
|
|
||||||
});
|
|
||||||
totalSize = diff.mismatch.size();
|
|
||||||
startTime = Instant.now();
|
|
||||||
updateState("UnknownFile", 0L, 100);
|
|
||||||
ListDownloader listDownloader = new ListDownloader();
|
|
||||||
LogHelper.info("Download %s to %s", dirName, dir.toAbsolutePath().toString());
|
|
||||||
if (e.zip && !adds.isEmpty()) {
|
|
||||||
listDownloader.downloadZip(e.url, adds, dir, this::updateState, (add) -> totalDownloaded += add, e.fullDownload);
|
|
||||||
} else {
|
|
||||||
listDownloader.download(e.url, adds, dir, this::updateState, (add) -> totalDownloaded += add);
|
|
||||||
}
|
|
||||||
if (controller != null) controller.postDownload(this, e);
|
|
||||||
deleteExtraDir(dir, diff.extra, diff.extra.flag);
|
|
||||||
if (controller != null) controller.postUpdate(this, e);
|
|
||||||
LogHelper.debug("Update success");
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance
|
// Instance
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private final String dirName;
|
private final String dirName;
|
||||||
private transient final Path dir;
|
|
||||||
|
|
||||||
public Path getDir() {
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
private transient final FileNameMatcher matcher;
|
|
||||||
|
|
||||||
private transient final boolean digest;
|
|
||||||
private transient volatile Callback stateCallback;
|
|
||||||
// State
|
|
||||||
private transient HashedDir localDir;
|
|
||||||
private transient long totalDownloaded;
|
|
||||||
|
|
||||||
private transient long totalSize;
|
|
||||||
|
|
||||||
private transient Instant startTime;
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public UpdateRequest(String dirName, Path dir, FileNameMatcher matcher, boolean digest) {
|
|
||||||
this.dirName = IOHelper.verifyFileName(dirName);
|
|
||||||
this.dir = Objects.requireNonNull(dir, "dir");
|
|
||||||
this.matcher = matcher;
|
|
||||||
this.digest = digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteExtraDir(Path subDir, HashedDir subHDir, boolean flag) throws IOException {
|
|
||||||
for (Entry<String, HashedEntry> mapEntry : subHDir.map().entrySet()) {
|
|
||||||
String name = mapEntry.getKey();
|
|
||||||
Path path = subDir.resolve(name);
|
|
||||||
|
|
||||||
// Delete list and dirs based on type
|
|
||||||
HashedEntry entry = mapEntry.getValue();
|
|
||||||
HashedEntry.Type entryType = entry.getType();
|
|
||||||
switch (entryType) {
|
|
||||||
case FILE:
|
|
||||||
updateState(IOHelper.toString(path), 0, 0);
|
|
||||||
Files.delete(path);
|
|
||||||
break;
|
|
||||||
case DIR:
|
|
||||||
deleteExtraDir(path, (HashedDir) entry, flag || entry.flag);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new AssertionError("Unsupported hashed entry type: " + entryType.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete!
|
|
||||||
if (flag) {
|
|
||||||
updateState(IOHelper.toString(subDir), 0, 0);
|
|
||||||
Files.delete(subDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UpdateRequestEvent request() throws Exception {
|
|
||||||
Files.createDirectories(dir);
|
|
||||||
localDir = new HashedDir(dir, matcher, false, digest);
|
|
||||||
|
|
||||||
// Start request
|
|
||||||
return super.request();
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public void setStateCallback(Callback callback) {
|
|
||||||
stateCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateState(String filePath, long fileDownloaded, long fileSize) {
|
|
||||||
if (stateCallback != null)
|
|
||||||
stateCallback.call(new State(filePath, fileDownloaded, fileSize,
|
|
||||||
totalDownloaded, totalSize, Duration.between(startTime, Instant.now())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit 3cf0cb41a64b1f05d76bdc67f83d67d80ebe41f1
|
Subproject commit f986d6b73705742b60a0db7feef2d8daacc43a5a
|
Loading…
Reference in a new issue