[FEATURE] Offline Mode

This commit is contained in:
Gravita 2021-11-16 23:00:41 +07:00
parent 111639b963
commit eecd61e6ba
17 changed files with 356 additions and 98 deletions

View file

@ -6,6 +6,7 @@
import pro.gravit.launcher.client.events.ClientPreGuiPhase;
import pro.gravit.launcher.console.GetPublicKeyCommand;
import pro.gravit.launcher.console.SignDataCommand;
import pro.gravit.launcher.events.request.*;
import pro.gravit.launcher.guard.LauncherGuardInterface;
import pro.gravit.launcher.guard.LauncherGuardManager;
import pro.gravit.launcher.guard.LauncherNoGuard;
@ -14,14 +15,21 @@
import pro.gravit.launcher.gui.RuntimeProvider;
import pro.gravit.launcher.managers.ClientGsonManager;
import pro.gravit.launcher.managers.ConsoleManager;
import pro.gravit.launcher.modules.events.OfflineModeEvent;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
import pro.gravit.launcher.request.RequestService;
import pro.gravit.launcher.request.auth.*;
import pro.gravit.launcher.request.auth.details.AuthLoginOnlyDetails;
import pro.gravit.launcher.request.management.FeaturesRequest;
import pro.gravit.launcher.request.secure.GetSecureLevelInfoRequest;
import pro.gravit.launcher.request.secure.SecurityReportRequest;
import pro.gravit.launcher.request.update.LauncherRequest;
import pro.gravit.launcher.request.websockets.ClientWebSocketService;
import pro.gravit.launcher.request.websockets.OfflineRequestService;
import pro.gravit.launcher.request.websockets.StdWebSocketService;
import pro.gravit.launcher.utils.NativeJVMHalt;
import pro.gravit.utils.helper.*;
@ -34,7 +42,9 @@
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@ -143,6 +153,35 @@ public static LauncherGuardInterface tryGetStdGuard() {
return null;
}
public static RequestService initOffline() {
OfflineRequestService service = new OfflineRequestService();
applyBasicOfflineProcessors(service);
OfflineModeEvent event = new OfflineModeEvent(service);
modulesManager.invokeEvent(event);
return event.service;
}
public static void applyBasicOfflineProcessors(OfflineRequestService service) {
service.registerRequestProcessor(LauncherRequest.class, (r) -> new LauncherRequestEvent(false, (String) null));
service.registerRequestProcessor(CheckServerRequest.class, (r) -> {
throw new RequestException("CheckServer disabled in offline mode");
});
service.registerRequestProcessor(GetAvailabilityAuthRequest.class, (r) -> {
List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> details = new ArrayList<>();
details.add(new AuthLoginOnlyDetails());
GetAvailabilityAuthRequestEvent.AuthAvailability authAvailability = new GetAvailabilityAuthRequestEvent.AuthAvailability("offline", "Offline Mode", details);
List<GetAvailabilityAuthRequestEvent.AuthAvailability> list = new ArrayList<>(1);
list.add(authAvailability);
return new GetAvailabilityAuthRequestEvent(list);
});
service.registerRequestProcessor(JoinServerRequest.class, (r) -> new JoinServerRequestEvent(false));
service.registerRequestProcessor(ExitRequest.class, (r) -> new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
service.registerRequestProcessor(SetProfileRequest.class, (r) -> new SetProfileRequestEvent(null));
service.registerRequestProcessor(FeaturesRequest.class, (r) -> new FeaturesRequestEvent());
service.registerRequestProcessor(GetSecureLevelInfoRequest.class, (r) -> new GetSecureLevelInfoRequestEvent(null, false));
service.registerRequestProcessor(SecurityReportRequest.class, (r) -> new SecurityReportRequestEvent(SecurityReportRequestEvent.ReportAction.NONE));
}
public static LauncherEngine clientInstance() {
return new LauncherEngine(true);
}
@ -193,18 +232,29 @@ public void start(String... args) throws Throwable {
if (!Request.isAvailable()) {
String address = Launcher.getConfig().address;
LogHelper.debug("Start async connection to %s", address);
StdWebSocketService service = StdWebSocketService.initWebSockets(address, true);
Request.setRequestService(service);
service.reconnectCallback = () ->
{
LogHelper.debug("WebSocket connect closed. Try reconnect");
try {
Request.reconnect();
} catch (Exception e) {
RequestService service;
try {
service = StdWebSocketService.initWebSockets(address).get();
} catch (Throwable e) {
if(LogHelper.isDebugEnabled()) {
LogHelper.error(e);
throw new RequestException("Connection failed", e);
}
};
LogHelper.warning("Launcher in offline mode");
service = initOffline();
}
Request.setRequestService(service);
if(service instanceof StdWebSocketService) {
((StdWebSocketService) service).reconnectCallback = () ->
{
LogHelper.debug("WebSocket connect closed. Try reconnect");
try {
Request.reconnect();
} catch (Exception e) {
LogHelper.error(e);
throw new RequestException("Connection failed", e);
}
};
}
service.registerEventHandler(new BasicLauncherEventHandler());
}
Objects.requireNonNull(args, "args");

View file

@ -4,12 +4,16 @@
import pro.gravit.launcher.api.AuthService;
import pro.gravit.launcher.api.ClientService;
import pro.gravit.launcher.client.events.client.*;
import pro.gravit.launcher.events.request.ProfileByUUIDRequestEvent;
import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent;
import pro.gravit.launcher.guard.LauncherGuardManager;
import pro.gravit.launcher.hasher.FileNameMatcher;
import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.hasher.HashedEntry;
import pro.gravit.launcher.managers.ClientGsonManager;
import pro.gravit.launcher.managers.ConsoleManager;
import pro.gravit.launcher.modules.LauncherModulesManager;
import pro.gravit.launcher.modules.events.OfflineModeEvent;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.patches.FMLPatcher;
import pro.gravit.launcher.profiles.ClientProfile;
@ -19,8 +23,13 @@
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.RequestService;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
import pro.gravit.launcher.request.uuid.BatchProfileByUsernameRequest;
import pro.gravit.launcher.request.uuid.ProfileByUUIDRequest;
import pro.gravit.launcher.request.uuid.ProfileByUsernameRequest;
import pro.gravit.launcher.request.websockets.OfflineRequestService;
import pro.gravit.launcher.request.websockets.StdWebSocketService;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.utils.DirWatcher;
@ -113,21 +122,25 @@ public static void main(String[] args) throws Throwable {
List<URL> classpath = resolveClassPath(clientDir, params.actions, params.profile).map(IOHelper::toURL).collect(Collectors.toList());
// Start client with WatchService monitoring
boolean digest = !profile.isUpdateFastCheck();
StdWebSocketService service = StdWebSocketService.initWebSockets(Launcher.getConfig().address, false);
LogHelper.debug("Restore sessions");
Request.restore();
service.registerEventHandler(new BasicLauncherEventHandler());
service.reconnectCallback = () ->
{
LogHelper.debug("WebSocket connect closed. Try reconnect");
try {
Request.reconnect();
} catch (Exception e) {
LogHelper.error(e);
throw new RequestException("Connection failed", e);
}
};
RequestService service;
if(params.offlineMode) {
service = initOffline(LauncherEngine.modulesManager, params);
} else {
service = StdWebSocketService.initWebSockets(Launcher.getConfig().address).get();
LogHelper.debug("Restore sessions");
Request.restore();
service.registerEventHandler(new BasicLauncherEventHandler());
((StdWebSocketService) service).reconnectCallback = () ->
{
LogHelper.debug("WebSocket connect closed. Try reconnect");
try {
Request.reconnect();
} catch (Exception e) {
LogHelper.error(e);
throw new RequestException("Connection failed", e);
}
};
}
Request.setRequestService(service);
ClientProfile.ClassLoaderConfig classLoaderConfig = profile.getClassLoaderConfig();
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
@ -204,6 +217,30 @@ private static void initGson(ClientModuleManager moduleManager) {
Launcher.gsonManager.initGson();
}
public static RequestService initOffline(LauncherModulesManager modulesManager, ClientLauncherProcess.ClientParams params) {
OfflineRequestService service = new OfflineRequestService();
LauncherEngine.applyBasicOfflineProcessors(service);
applyClientOfflineProcessors(service, params);
OfflineModeEvent event = new OfflineModeEvent(service);
modulesManager.invokeEvent(event);
return event.service;
}
public static void applyClientOfflineProcessors(OfflineRequestService service, ClientLauncherProcess.ClientParams params) {
service.registerRequestProcessor(ProfileByUsernameRequest.class, (r) -> {
if(params.playerProfile.username.equals(r.username)) {
return new ProfileByUsernameRequestEvent(params.playerProfile);
}
throw new RequestException("User not found");
});
service.registerRequestProcessor(ProfileByUUIDRequest.class, (r) -> {
if(params.playerProfile.uuid.equals(r.uuid)) {
return new ProfileByUUIDRequestEvent(params.playerProfile);
}
throw new RequestException("User not found");
});
}
public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest) throws IOException {
//if (matcher != null)
// matcher = matcher.verifyOnly();

View file

@ -281,6 +281,8 @@ public static class ClientParams {
public Map<String, String> extendedTokens;
public boolean offlineMode;
public transient HashedDir assetHDir;
public transient HashedDir clientHDir;

View file

@ -7,7 +7,12 @@
import pro.gravit.launcher.client.ClientModuleManager;
import pro.gravit.launcher.managers.ConsoleManager;
import pro.gravit.launcher.modules.LauncherModule;
import pro.gravit.launcher.modules.events.OfflineModeEvent;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestService;
import pro.gravit.launcher.request.websockets.OfflineRequestService;
import pro.gravit.launcher.request.websockets.StdWebSocketService;
import pro.gravit.utils.helper.LogHelper;
import java.lang.invoke.MethodHandles;
@ -22,6 +27,7 @@ public class DebugMain {
public static String webSocketURL = System.getProperty("launcherdebug.websocket", "ws://localhost:9274/api");
public static String projectName = System.getProperty("launcherdebug.projectname", "Minecraft");
public static String unlockKey = System.getProperty("launcherdebug.unlockkey", "0000");
public static boolean offlineMode = Boolean.getBoolean("launcherdebug.offlinemode");
public static String[] moduleClasses = System.getProperty("launcherdebug.modules", "").split(",");
public static String[] moduleFiles = System.getProperty("launcherdebug.modulefiles", "").split(",");
public static LauncherConfig.LauncherEnvironment environment = LauncherConfig.LauncherEnvironment.valueOf(System.getProperty("launcherdebug.env", "STD"));
@ -50,6 +56,17 @@ public static void main(String[] args) throws Throwable {
LauncherEngine.initGson(LauncherEngine.modulesManager);
ConsoleManager.initConsole();
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
RequestService service;
if(offlineMode) {
OfflineRequestService offlineRequestService = new OfflineRequestService();
LauncherEngine.applyBasicOfflineProcessors(offlineRequestService);
OfflineModeEvent event = new OfflineModeEvent(offlineRequestService);
LauncherEngine.modulesManager.invokeEvent(event);
service = event.service;
} else {
service = StdWebSocketService.initWebSockets(webSocketURL).get();
}
Request.setRequestService(service);
LogHelper.debug("Initialization LauncherEngine");
LauncherEngine instance = LauncherEngine.newInstance(false);
instance.start(args);

View file

@ -10,6 +10,11 @@ public GetSecureLevelInfoRequestEvent(byte[] verifySecureKey) {
this.verifySecureKey = verifySecureKey;
}
public GetSecureLevelInfoRequestEvent(byte[] verifySecureKey, boolean enabled) {
this.verifySecureKey = verifySecureKey;
this.enabled = enabled;
}
@Override
public String getType() {
return "getSecureLevelInfo";

View file

@ -0,0 +1,12 @@
package pro.gravit.launcher.modules.events;
import pro.gravit.launcher.modules.LauncherModule;
import pro.gravit.launcher.request.RequestService;
public class OfflineModeEvent extends LauncherModule.Event {
public RequestService service;
public OfflineModeEvent(RequestService service) {
this.service = service;
}
}

View file

@ -214,8 +214,9 @@ public void removeOAuthChangeHandler(BiConsumer<String, AuthRequestEvent.OAuthRe
public R request() throws Exception {
if (!started.compareAndSet(false, true))
throw new IllegalStateException("Request already started");
if (!isAvailable())
setRequestService(StdWebSocketService.initWebSockets(Launcher.getConfig().address, false));
if(!isAvailable()) {
throw new RequestException("RequestService not initialized");
}
return requestDo(requestService);
}

View file

@ -11,15 +11,15 @@ public final class AuthRequest extends Request<AuthRequestEvent> implements WebS
public static final ProviderMap<AuthPasswordInterface> providers = new ProviderMap<>();
private static boolean registerProviders = false;
@LauncherNetworkAPI
private final String login;
public final String login;
@LauncherNetworkAPI
private final AuthPasswordInterface password;
public final AuthPasswordInterface password;
@LauncherNetworkAPI
private final String auth_id;
public final String auth_id;
@LauncherNetworkAPI
private final boolean getSession;
public final boolean getSession;
@LauncherNetworkAPI
private final ConnectTypes authType;
public final ConnectTypes authType;
public AuthRequest(String login, String password, String auth_id, ConnectTypes authType) {
this.login = login;

View file

@ -24,6 +24,8 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public abstract class ClientJSONPoint {
@ -94,16 +96,26 @@ public void open() throws Exception {
webSocketClientHandler.handshakeFuture().sync();
}
public void openAsync(Runnable onConnect) {
public void openAsync(Runnable onConnect, Consumer<Throwable> onFail) {
//System.out.println("WebSocket Client connecting");
webSocketClientHandler =
new WebSocketClientHandler(
WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, false, EmptyHttpHeaders.INSTANCE, 12800000), this);
ChannelFuture future = bootstrap.connect(uri.getHost(), port);
future.addListener((e) -> {
ch = future.channel();
webSocketClientHandler.handshakeFuture().addListener((e1) -> onConnect.run());
future.addListener((l) -> {
if(l.isSuccess()) {
ch = future.channel();
webSocketClientHandler.handshakeFuture().addListener((e) -> {
if(e.isSuccess()) {
onConnect.run();
} else {
onFail.accept(webSocketClientHandler.handshakeFuture().cause());
}
});
} else {
onFail.accept(future.cause());
}
});
}

View file

@ -27,6 +27,7 @@
public abstract class ClientWebSocketService extends ClientJSONPoint {
public static final ProviderMap<WebSocketEvent> results = new ProviderMap<>();
public static final ProviderMap<WebSocketRequest> requests = new ProviderMap<>();
private static boolean resultsRegistered = false;
public final Gson gson;
public final Boolean onConnect;
public OnCloseCallback onCloseCallback;
@ -83,38 +84,41 @@ public void registerRequests() {
@SuppressWarnings("deprecation")
public void registerResults() {
results.register("auth", AuthRequestEvent.class);
results.register("checkServer", CheckServerRequestEvent.class);
results.register("joinServer", JoinServerRequestEvent.class);
results.register("launcher", LauncherRequestEvent.class);
results.register("profileByUsername", ProfileByUsernameRequestEvent.class);
results.register("profileByUUID", ProfileByUUIDRequestEvent.class);
results.register("batchProfileByUsername", BatchProfileByUsernameRequestEvent.class);
results.register("profiles", ProfilesRequestEvent.class);
results.register("setProfile", SetProfileRequestEvent.class);
results.register("updateList", UpdateListRequestEvent.class);
results.register("error", ErrorRequestEvent.class);
results.register("update", UpdateRequestEvent.class);
results.register("restoreSession", RestoreSessionRequestEvent.class);
results.register("log", LogEvent.class);
results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class);
results.register("exception", ExceptionEvent.class);
results.register("register", RegisterRequestEvent.class);
results.register("notification", NotificationEvent.class);
results.register("signal", SignalEvent.class);
results.register("exit", ExitRequestEvent.class);
results.register("getSecureLevelInfo", GetSecureLevelInfoRequestEvent.class);
results.register("verifySecureLevelKey", VerifySecureLevelKeyRequestEvent.class);
results.register("securityReport", SecurityReportRequestEvent.class);
results.register("hardwareReport", HardwareReportRequestEvent.class);
results.register("serverStatus", ServerStatusRequestEvent.class);
results.register("pingServerReport", PingServerReportRequestEvent.class);
results.register("pingServer", PingServerRequestEvent.class);
results.register("currentUser", CurrentUserRequestEvent.class);
results.register("features", FeaturesRequestEvent.class);
results.register("refreshToken", RefreshTokenRequestEvent.class);
results.register("restore", RestoreRequestEvent.class);
results.register("additionalData", AdditionalDataRequestEvent.class);
if(!resultsRegistered) {
results.register("auth", AuthRequestEvent.class);
results.register("checkServer", CheckServerRequestEvent.class);
results.register("joinServer", JoinServerRequestEvent.class);
results.register("launcher", LauncherRequestEvent.class);
results.register("profileByUsername", ProfileByUsernameRequestEvent.class);
results.register("profileByUUID", ProfileByUUIDRequestEvent.class);
results.register("batchProfileByUsername", BatchProfileByUsernameRequestEvent.class);
results.register("profiles", ProfilesRequestEvent.class);
results.register("setProfile", SetProfileRequestEvent.class);
results.register("updateList", UpdateListRequestEvent.class);
results.register("error", ErrorRequestEvent.class);
results.register("update", UpdateRequestEvent.class);
results.register("restoreSession", RestoreSessionRequestEvent.class);
results.register("log", LogEvent.class);
results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class);
results.register("exception", ExceptionEvent.class);
results.register("register", RegisterRequestEvent.class);
results.register("notification", NotificationEvent.class);
results.register("signal", SignalEvent.class);
results.register("exit", ExitRequestEvent.class);
results.register("getSecureLevelInfo", GetSecureLevelInfoRequestEvent.class);
results.register("verifySecureLevelKey", VerifySecureLevelKeyRequestEvent.class);
results.register("securityReport", SecurityReportRequestEvent.class);
results.register("hardwareReport", HardwareReportRequestEvent.class);
results.register("serverStatus", ServerStatusRequestEvent.class);
results.register("pingServerReport", PingServerReportRequestEvent.class);
results.register("pingServer", PingServerRequestEvent.class);
results.register("currentUser", CurrentUserRequestEvent.class);
results.register("features", FeaturesRequestEvent.class);
results.register("refreshToken", RefreshTokenRequestEvent.class);
results.register("restore", RestoreRequestEvent.class);
results.register("additionalData", AdditionalDataRequestEvent.class);
resultsRegistered = true;
}
}
public void waitIfNotConnected() {

View file

@ -0,0 +1,73 @@
package pro.gravit.launcher.request.websockets;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.RequestService;
import pro.gravit.launcher.request.WebSocketEvent;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
public class OfflineRequestService implements RequestService {
private final HashSet<EventHandler> eventHandlers = new HashSet<>();
private final Map<Class<?>, RequestProcessor<?, ?>> processors = new ConcurrentHashMap<>();
@Override
@SuppressWarnings("unchecked")
public <T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) throws IOException {
RequestProcessor<T, Request<T>> processor = (RequestProcessor<T, Request<T>>) processors.get(request.getClass());
CompletableFuture<T> future = new CompletableFuture<>();
if(processor == null) {
future.completeExceptionally(new RequestException(String.format("Offline mode not support '%s'", request.getType())));
return future;
}
if(LogHelper.isDevEnabled()) {
LogHelper.dev("Request %s: %s", request.getType(), Launcher.gsonManager.gson.toJson(request));
}
try {
T event = processor.process(request);
if(LogHelper.isDevEnabled()) {
LogHelper.dev("Response %s: %s", event.getType(), Launcher.gsonManager.gson.toJson(event));
}
future.complete(event);
} catch (Throwable e) {
if(e instanceof RequestException) {
future.completeExceptionally(e);
} else {
future.completeExceptionally(new RequestException(e));
}
}
return future;
}
@Override
public void registerEventHandler(EventHandler handler) {
eventHandlers.add(handler);
}
@Override
public void unregisterEventHandler(EventHandler handler) {
eventHandlers.remove(handler);
}
@Override
public boolean isClosed() {
return false;
}
public<T extends WebSocketEvent, V extends WebSocketRequest> void registerRequestProcessor(Class<V> requestClazz, RequestProcessor<T, V> function) {
processors.put(requestClazz, function);
}
public<T extends WebSocketEvent> void unregisterRequestProcessor(Class<Request<T>> requestClazz) {
processors.remove(requestClazz);
}
public interface RequestProcessor<T extends WebSocketEvent, V extends WebSocketRequest> {
T process(V request) throws RequestException;
}
}

View file

@ -28,7 +28,7 @@ public StdWebSocketService(String address) throws SSLException {
super(address);
}
public static StdWebSocketService initWebSockets(String address, boolean async) {
public static CompletableFuture<StdWebSocketService> initWebSockets(String address) throws Exception {
StdWebSocketService service;
try {
service = new StdWebSocketService(address);
@ -37,28 +37,26 @@ public static StdWebSocketService initWebSockets(String address, boolean async)
}
service.registerResults();
service.registerRequests();
if (!async) {
try {
service.open();
} catch (Exception e) {
LogHelper.error(e);
}
} else {
service.openAsync(() -> {
});
}
JVMHelper.RUNTIME.addShutdownHook(new Thread(() -> {
try {
//if(service.isOpen())
// service.closeBlocking();
service.close();
} catch (InterruptedException e) {
LogHelper.error(e);
}
}));
return service;
CompletableFuture<StdWebSocketService> future = new CompletableFuture<>();
service.openAsync(() -> {
future.complete(service);
JVMHelper.RUNTIME.addShutdownHook(new Thread(() -> {
try {
//if(service.isOpen())
// service.closeBlocking();
service.close();
} catch (InterruptedException e) {
LogHelper.error(e);
}
}));
}, (error) -> {
future.completeExceptionally(error);
});
return future;
}
@Deprecated
public void registerEventHandler(ClientWebSocketService.EventHandler handler) {
legacyEventHandlers.add(handler);

View file

@ -0,0 +1,43 @@
package pro.gravit.launcher.request.websockets;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.RequestService;
import pro.gravit.launcher.request.WebSocketEvent;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
public class VoidRequestService implements RequestService {
private final Throwable ex;
public VoidRequestService(Throwable ex) {
this.ex = ex;
}
public VoidRequestService() {
this.ex = null;
}
@Override
public <T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) throws IOException {
CompletableFuture<T> future = new CompletableFuture<>();
future.completeExceptionally(ex != null ? ex : new RequestException("Connection fail"));
return future;
}
@Override
public void registerEventHandler(EventHandler handler) {
}
@Override
public void unregisterEventHandler(EventHandler handler) {
}
@Override
public boolean isClosed() {
return true;
}
}

View file

@ -77,17 +77,15 @@ else if (frame instanceof BinaryWebSocketFrame) {
// uncomment to print request
// logger.info(frame.content().toString());
}
}
@Override
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
LogHelper.error(cause);
if (!handshakeFuture.isDone()) {
handshakeFuture.setFailure(cause);
} else {
LogHelper.error(cause);
}
ctx.close();
}
}

View file

@ -113,7 +113,7 @@ public void run(String... args) throws Throwable {
updateLauncherConfig();
if (config.env != null) Launcher.applyLauncherEnv(config.env);
else Launcher.applyLauncherEnv(LauncherConfig.LauncherEnvironment.STD);
StdWebSocketService service = StdWebSocketService.initWebSockets(config.address, false);
StdWebSocketService service = StdWebSocketService.initWebSockets(config.address).get();
service.reconnectCallback = () ->
{
LogHelper.debug("WebSocket connect closed. Try reconnect");

View file

@ -61,7 +61,13 @@ public void run() throws Exception {
if(!Request.isAvailable() || Request.getRequestService().isClosed()) {
System.out.println("Print launchserver websocket host( ws://host:port/api ):");
wrapper.config.address = commands.commandHandler.readLine();
StdWebSocketService service = StdWebSocketService.initWebSockets(wrapper.config.address, false);
StdWebSocketService service;
try {
service = StdWebSocketService.initWebSockets(wrapper.config.address).get();
} catch (Throwable e) {
LogHelper.error(e);
continue;
}
Request.setRequestService(service);
}
System.out.println("Print server token:");

View file

@ -5,7 +5,7 @@
id 'org.openjfx.javafxplugin' version '0.0.10' apply false
}
group = 'pro.gravit.launcher'
version = '5.2.5'
version = '5.2.6-SNAPSHOT'
apply from: 'props.gradle'