完善 HiPer 支持 (#1821)

* Display hiper token expiration time

* Automatically download missing files when starting HiPer

* Disable start HiPer when token is empty
This commit is contained in:
Glavo 2022-11-05 19:36:17 +08:00 committed by GitHub
parent 8687bb9487
commit af107b15c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 38 additions and 35 deletions

View File

@ -18,6 +18,7 @@
package org.jackhuang.hmcl.ui.multiplayer;
import com.google.gson.JsonParseException;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import org.jackhuang.hmcl.Metadata;
@ -26,9 +27,9 @@ import org.jackhuang.hmcl.event.EventManager;
import org.jackhuang.hmcl.setting.ConfigHolder;
import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.*;
import org.jackhuang.hmcl.util.gson.DateTypeAdapter;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.HttpRequest;
@ -44,6 +45,9 @@ import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.PosixFilePermission;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@ -54,6 +58,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
import static org.jackhuang.hmcl.util.Lang.*;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.io.ChecksumMismatchException.verifyChecksum;
/**
@ -105,9 +110,14 @@ public final class MultiplayerManager {
static final boolean IS_ADMINISTRATOR;
static final BooleanBinding tokenInvalid = Bindings.createBooleanBinding(
() -> !StringUtils.isAlphabeticOrNumber(globalConfig().multiplayerTokenProperty().getValue()),
() -> {
String token = globalConfig().multiplayerTokenProperty().getValue();
return token == null || token.isEmpty() || !StringUtils.isAlphabeticOrNumber(token);
},
globalConfig().multiplayerTokenProperty());
private static final DateFormat HIPER_VALID_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
static {
boolean isAdministrator = false;
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
@ -220,11 +230,8 @@ public final class MultiplayerManager {
}
public static CompletableFuture<HiperSession> startHiper(String token) {
return getPackagesHash().thenApplyAsync(wrap(packagesHash -> {
if (!Files.isRegularFile(HIPER_PATH)) {
throw new HiperNotExistsException(HIPER_PATH);
}
return getPackagesHash().thenComposeAsync(packagesHash -> {
CompletableFuture<Void> future = new CompletableFuture<>();
try {
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
verifyChecksum(getHiperLocalDirectory().resolve("hiper.exe"), "SHA-1", packagesHash.get(String.format("%s/hiper.exe", HIPER_TARGET_NAME)));
@ -235,12 +242,20 @@ public final class MultiplayerManager {
} else {
verifyChecksum(getHiperLocalDirectory().resolve("hiper"), "SHA-1", packagesHash.get(String.format("%s/hiper", HIPER_TARGET_NAME)));
}
} catch (IOException e) {
// force redownload
Files.deleteIfExists(HIPER_PATH);
throw e;
}
future.complete(null);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to verify HiPer files", e);
Platform.runLater(() -> Controllers.taskDialog(MultiplayerManager.downloadHiper()
.whenComplete(exception -> {
if (exception == null)
future.complete(null);
else
future.completeExceptionally(exception);
}), i18n("multiplayer.download"), TaskCancellationAction.NORMAL));
}
return future;
}).thenApplyAsync(wrap(ignored -> {
Path configPath = getConfigPath(token);
Files.createDirectories(configPath.getParent());
@ -361,9 +376,11 @@ public final class MultiplayerManager {
Optional<String> validUntil = tryCast(logJson.get("valid"), String.class);
if (validUntil.isPresent()) {
try {
Date date = DateTypeAdapter.deserializeToDate(validUntil.get());
onValidUntil.fireEvent(new HiperShowValidUntilEvent(this, date));
} catch (JsonParseException e) {
synchronized (HIPER_VALID_TIME_FORMAT) {
Date date = HIPER_VALID_TIME_FORMAT.parse(validUntil.get());
onValidUntil.fireEvent(new HiperShowValidUntilEvent(this, date));
}
} catch (JsonParseException | ParseException e) {
LOG.log(Level.WARNING, "Failed to parse certification expire time string: " + validUntil.get());
}
}
@ -527,18 +544,6 @@ public final class MultiplayerManager {
}
}
public static class HiperNotExistsException extends RuntimeException {
private final Path file;
public HiperNotExistsException(Path file) {
this.file = file;
}
public Path getFile() {
return file;
}
}
public static class HiperInvalidTokenException extends RuntimeException {
}

View File

@ -217,11 +217,8 @@ public class MultiplayerPage extends DecoratorAnimatedPage implements DecoratorP
} else if (e instanceof MultiplayerManager.HiperInvalidConfigurationException) {
LOG.warning("HiPer invalid configuration");
return i18n("multiplayer.token.malformed");
} else if (e instanceof MultiplayerManager.HiperNotExistsException) {
LOG.log(Level.WARNING, "Hiper not found " + ((MultiplayerManager.HiperNotExistsException) e).getFile(), e);
return i18n("multiplayer.error.file_not_found");
} else if (e instanceof ChecksumMismatchException) {
LOG.log(Level.WARNING, "HiPer files are not verified", e);
LOG.log(Level.WARNING, "Failed to verify HiPer files", e);
return i18n("multiplayer.error.file_not_found");
} else if (e instanceof MultiplayerManager.HiperExitException) {
int exitCode = ((MultiplayerManager.HiperExitException) e).getExitCode();
@ -284,6 +281,7 @@ public class MultiplayerPage extends DecoratorAnimatedPage implements DecoratorP
private void clearSession() {
this.session.set(null);
this.expireTime.set(null);
this.onExit = null;
this.onIPAllocated = null;
this.onValidUntil = null;

View File

@ -184,7 +184,7 @@ public class MultiplayerPageSkin extends DecoratorAnimatedPage.DecoratorAnimated
expirationLabel.textProperty().bind(Bindings.createStringBinding(() ->
control.getExpireTime() == null ? "" : Locales.SIMPLE_DATE_FORMAT.get().format(control.getExpireTime()),
control.expireTimeProperty()));
expirationPane.setCenter(expirationLabel);
expirationPane.setRight(expirationLabel);
GridPane masterPane = new GridPane();
masterPane.setVgap(8);

View File

@ -907,7 +907,7 @@ multiplayer.slave.server_address=Creator server address
multiplayer.slave.server_address.start=Join
multiplayer.slave.server_address.stop=Exit
multiplayer.slave.video_tutorial=Video Tutorial
multiplayer.session.expiration=Expire Time
multiplayer.session.expiration=Token Expiration Time
datapack=Datapacks
datapack.add=Install datapack

View File

@ -752,7 +752,7 @@ multiplayer.slave.server_address=創建方伺服器地址
multiplayer.slave.server_address.start=加入
multiplayer.slave.server_address.stop=退出
multiplayer.slave.video_tutorial=教學影片
multiplayer.session.expiration=本次使用截止時間
multiplayer.session.expiration=索引碼到期時間
datapack=資料包
datapack.add=加入資料包

View File

@ -752,7 +752,7 @@ multiplayer.slave.server_address=创建方服务器地址
multiplayer.slave.server_address.start=加入
multiplayer.slave.server_address.stop=退出
multiplayer.slave.video_tutorial=参与者视频教程
multiplayer.session.expiration=本次使用截止时间
multiplayer.session.expiration=索引码到期时间
datapack=数据包
datapack.add=添加数据包