mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 03:31:15 +03:00
[FEATURE] Offline Mode
This commit is contained in:
parent
111639b963
commit
eecd61e6ba
17 changed files with 356 additions and 98 deletions
|
@ -6,6 +6,7 @@
|
||||||
import pro.gravit.launcher.client.events.ClientPreGuiPhase;
|
import pro.gravit.launcher.client.events.ClientPreGuiPhase;
|
||||||
import pro.gravit.launcher.console.GetPublicKeyCommand;
|
import pro.gravit.launcher.console.GetPublicKeyCommand;
|
||||||
import pro.gravit.launcher.console.SignDataCommand;
|
import pro.gravit.launcher.console.SignDataCommand;
|
||||||
|
import pro.gravit.launcher.events.request.*;
|
||||||
import pro.gravit.launcher.guard.LauncherGuardInterface;
|
import pro.gravit.launcher.guard.LauncherGuardInterface;
|
||||||
import pro.gravit.launcher.guard.LauncherGuardManager;
|
import pro.gravit.launcher.guard.LauncherGuardManager;
|
||||||
import pro.gravit.launcher.guard.LauncherNoGuard;
|
import pro.gravit.launcher.guard.LauncherNoGuard;
|
||||||
|
@ -14,14 +15,21 @@
|
||||||
import pro.gravit.launcher.gui.RuntimeProvider;
|
import pro.gravit.launcher.gui.RuntimeProvider;
|
||||||
import pro.gravit.launcher.managers.ClientGsonManager;
|
import pro.gravit.launcher.managers.ClientGsonManager;
|
||||||
import pro.gravit.launcher.managers.ConsoleManager;
|
import pro.gravit.launcher.managers.ConsoleManager;
|
||||||
|
import pro.gravit.launcher.modules.events.OfflineModeEvent;
|
||||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||||
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
|
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
|
||||||
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
|
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
|
||||||
import pro.gravit.launcher.request.Request;
|
import pro.gravit.launcher.request.Request;
|
||||||
import pro.gravit.launcher.request.RequestException;
|
import pro.gravit.launcher.request.RequestException;
|
||||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
import pro.gravit.launcher.request.RequestService;
|
||||||
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
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.ClientWebSocketService;
|
||||||
|
import pro.gravit.launcher.request.websockets.OfflineRequestService;
|
||||||
import pro.gravit.launcher.request.websockets.StdWebSocketService;
|
import pro.gravit.launcher.request.websockets.StdWebSocketService;
|
||||||
import pro.gravit.launcher.utils.NativeJVMHalt;
|
import pro.gravit.launcher.utils.NativeJVMHalt;
|
||||||
import pro.gravit.utils.helper.*;
|
import pro.gravit.utils.helper.*;
|
||||||
|
@ -34,7 +42,9 @@
|
||||||
import java.security.interfaces.ECPrivateKey;
|
import java.security.interfaces.ECPrivateKey;
|
||||||
import java.security.interfaces.ECPublicKey;
|
import java.security.interfaces.ECPublicKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
@ -143,6 +153,35 @@ public static LauncherGuardInterface tryGetStdGuard() {
|
||||||
return null;
|
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() {
|
public static LauncherEngine clientInstance() {
|
||||||
return new LauncherEngine(true);
|
return new LauncherEngine(true);
|
||||||
}
|
}
|
||||||
|
@ -193,18 +232,29 @@ public void start(String... args) throws Throwable {
|
||||||
if (!Request.isAvailable()) {
|
if (!Request.isAvailable()) {
|
||||||
String address = Launcher.getConfig().address;
|
String address = Launcher.getConfig().address;
|
||||||
LogHelper.debug("Start async connection to %s", address);
|
LogHelper.debug("Start async connection to %s", address);
|
||||||
StdWebSocketService service = StdWebSocketService.initWebSockets(address, true);
|
RequestService service;
|
||||||
Request.setRequestService(service);
|
try {
|
||||||
service.reconnectCallback = () ->
|
service = StdWebSocketService.initWebSockets(address).get();
|
||||||
{
|
} catch (Throwable e) {
|
||||||
LogHelper.debug("WebSocket connect closed. Try reconnect");
|
if(LogHelper.isDebugEnabled()) {
|
||||||
try {
|
|
||||||
Request.reconnect();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogHelper.error(e);
|
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());
|
service.registerEventHandler(new BasicLauncherEventHandler());
|
||||||
}
|
}
|
||||||
Objects.requireNonNull(args, "args");
|
Objects.requireNonNull(args, "args");
|
||||||
|
|
|
@ -4,12 +4,16 @@
|
||||||
import pro.gravit.launcher.api.AuthService;
|
import pro.gravit.launcher.api.AuthService;
|
||||||
import pro.gravit.launcher.api.ClientService;
|
import pro.gravit.launcher.api.ClientService;
|
||||||
import pro.gravit.launcher.client.events.client.*;
|
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.guard.LauncherGuardManager;
|
||||||
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.hasher.HashedEntry;
|
import pro.gravit.launcher.hasher.HashedEntry;
|
||||||
import pro.gravit.launcher.managers.ClientGsonManager;
|
import pro.gravit.launcher.managers.ClientGsonManager;
|
||||||
import pro.gravit.launcher.managers.ConsoleManager;
|
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.modules.events.PreConfigPhase;
|
||||||
import pro.gravit.launcher.patches.FMLPatcher;
|
import pro.gravit.launcher.patches.FMLPatcher;
|
||||||
import pro.gravit.launcher.profiles.ClientProfile;
|
import pro.gravit.launcher.profiles.ClientProfile;
|
||||||
|
@ -19,8 +23,13 @@
|
||||||
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
|
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
|
||||||
import pro.gravit.launcher.request.Request;
|
import pro.gravit.launcher.request.Request;
|
||||||
import pro.gravit.launcher.request.RequestException;
|
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.AuthRequest;
|
||||||
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
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.request.websockets.StdWebSocketService;
|
||||||
import pro.gravit.launcher.serialize.HInput;
|
import pro.gravit.launcher.serialize.HInput;
|
||||||
import pro.gravit.launcher.utils.DirWatcher;
|
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());
|
List<URL> classpath = resolveClassPath(clientDir, params.actions, params.profile).map(IOHelper::toURL).collect(Collectors.toList());
|
||||||
// Start client with WatchService monitoring
|
// Start client with WatchService monitoring
|
||||||
boolean digest = !profile.isUpdateFastCheck();
|
boolean digest = !profile.isUpdateFastCheck();
|
||||||
StdWebSocketService service = StdWebSocketService.initWebSockets(Launcher.getConfig().address, false);
|
RequestService service;
|
||||||
LogHelper.debug("Restore sessions");
|
if(params.offlineMode) {
|
||||||
Request.restore();
|
service = initOffline(LauncherEngine.modulesManager, params);
|
||||||
|
} else {
|
||||||
service.registerEventHandler(new BasicLauncherEventHandler());
|
service = StdWebSocketService.initWebSockets(Launcher.getConfig().address).get();
|
||||||
service.reconnectCallback = () ->
|
LogHelper.debug("Restore sessions");
|
||||||
{
|
Request.restore();
|
||||||
LogHelper.debug("WebSocket connect closed. Try reconnect");
|
service.registerEventHandler(new BasicLauncherEventHandler());
|
||||||
try {
|
((StdWebSocketService) service).reconnectCallback = () ->
|
||||||
Request.reconnect();
|
{
|
||||||
} catch (Exception e) {
|
LogHelper.debug("WebSocket connect closed. Try reconnect");
|
||||||
LogHelper.error(e);
|
try {
|
||||||
throw new RequestException("Connection failed", e);
|
Request.reconnect();
|
||||||
}
|
} catch (Exception e) {
|
||||||
};
|
LogHelper.error(e);
|
||||||
|
throw new RequestException("Connection failed", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Request.setRequestService(service);
|
Request.setRequestService(service);
|
||||||
ClientProfile.ClassLoaderConfig classLoaderConfig = profile.getClassLoaderConfig();
|
ClientProfile.ClassLoaderConfig classLoaderConfig = profile.getClassLoaderConfig();
|
||||||
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
|
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
|
||||||
|
@ -204,6 +217,30 @@ private static void initGson(ClientModuleManager moduleManager) {
|
||||||
Launcher.gsonManager.initGson();
|
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 {
|
public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest) throws IOException {
|
||||||
//if (matcher != null)
|
//if (matcher != null)
|
||||||
// matcher = matcher.verifyOnly();
|
// matcher = matcher.verifyOnly();
|
||||||
|
|
|
@ -281,6 +281,8 @@ public static class ClientParams {
|
||||||
|
|
||||||
public Map<String, String> extendedTokens;
|
public Map<String, String> extendedTokens;
|
||||||
|
|
||||||
|
public boolean offlineMode;
|
||||||
|
|
||||||
public transient HashedDir assetHDir;
|
public transient HashedDir assetHDir;
|
||||||
|
|
||||||
public transient HashedDir clientHDir;
|
public transient HashedDir clientHDir;
|
||||||
|
|
|
@ -7,7 +7,12 @@
|
||||||
import pro.gravit.launcher.client.ClientModuleManager;
|
import pro.gravit.launcher.client.ClientModuleManager;
|
||||||
import pro.gravit.launcher.managers.ConsoleManager;
|
import pro.gravit.launcher.managers.ConsoleManager;
|
||||||
import pro.gravit.launcher.modules.LauncherModule;
|
import pro.gravit.launcher.modules.LauncherModule;
|
||||||
|
import pro.gravit.launcher.modules.events.OfflineModeEvent;
|
||||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
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 pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
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 webSocketURL = System.getProperty("launcherdebug.websocket", "ws://localhost:9274/api");
|
||||||
public static String projectName = System.getProperty("launcherdebug.projectname", "Minecraft");
|
public static String projectName = System.getProperty("launcherdebug.projectname", "Minecraft");
|
||||||
public static String unlockKey = System.getProperty("launcherdebug.unlockkey", "0000");
|
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[] moduleClasses = System.getProperty("launcherdebug.modules", "").split(",");
|
||||||
public static String[] moduleFiles = System.getProperty("launcherdebug.modulefiles", "").split(",");
|
public static String[] moduleFiles = System.getProperty("launcherdebug.modulefiles", "").split(",");
|
||||||
public static LauncherConfig.LauncherEnvironment environment = LauncherConfig.LauncherEnvironment.valueOf(System.getProperty("launcherdebug.env", "STD"));
|
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);
|
LauncherEngine.initGson(LauncherEngine.modulesManager);
|
||||||
ConsoleManager.initConsole();
|
ConsoleManager.initConsole();
|
||||||
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
|
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");
|
LogHelper.debug("Initialization LauncherEngine");
|
||||||
LauncherEngine instance = LauncherEngine.newInstance(false);
|
LauncherEngine instance = LauncherEngine.newInstance(false);
|
||||||
instance.start(args);
|
instance.start(args);
|
||||||
|
|
|
@ -10,6 +10,11 @@ public GetSecureLevelInfoRequestEvent(byte[] verifySecureKey) {
|
||||||
this.verifySecureKey = verifySecureKey;
|
this.verifySecureKey = verifySecureKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GetSecureLevelInfoRequestEvent(byte[] verifySecureKey, boolean enabled) {
|
||||||
|
this.verifySecureKey = verifySecureKey;
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return "getSecureLevelInfo";
|
return "getSecureLevelInfo";
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -214,8 +214,9 @@ public void removeOAuthChangeHandler(BiConsumer<String, AuthRequestEvent.OAuthRe
|
||||||
public R request() throws Exception {
|
public R request() throws Exception {
|
||||||
if (!started.compareAndSet(false, true))
|
if (!started.compareAndSet(false, true))
|
||||||
throw new IllegalStateException("Request already started");
|
throw new IllegalStateException("Request already started");
|
||||||
if (!isAvailable())
|
if(!isAvailable()) {
|
||||||
setRequestService(StdWebSocketService.initWebSockets(Launcher.getConfig().address, false));
|
throw new RequestException("RequestService not initialized");
|
||||||
|
}
|
||||||
return requestDo(requestService);
|
return requestDo(requestService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,15 @@ public final class AuthRequest extends Request<AuthRequestEvent> implements WebS
|
||||||
public static final ProviderMap<AuthPasswordInterface> providers = new ProviderMap<>();
|
public static final ProviderMap<AuthPasswordInterface> providers = new ProviderMap<>();
|
||||||
private static boolean registerProviders = false;
|
private static boolean registerProviders = false;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private final String login;
|
public final String login;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private final AuthPasswordInterface password;
|
public final AuthPasswordInterface password;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private final String auth_id;
|
public final String auth_id;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private final boolean getSession;
|
public final boolean getSession;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private final ConnectTypes authType;
|
public final ConnectTypes authType;
|
||||||
|
|
||||||
public AuthRequest(String login, String password, String auth_id, ConnectTypes authType) {
|
public AuthRequest(String login, String password, String auth_id, ConnectTypes authType) {
|
||||||
this.login = login;
|
this.login = login;
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public abstract class ClientJSONPoint {
|
public abstract class ClientJSONPoint {
|
||||||
|
|
||||||
|
@ -94,16 +96,26 @@ public void open() throws Exception {
|
||||||
webSocketClientHandler.handshakeFuture().sync();
|
webSocketClientHandler.handshakeFuture().sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openAsync(Runnable onConnect) {
|
public void openAsync(Runnable onConnect, Consumer<Throwable> onFail) {
|
||||||
//System.out.println("WebSocket Client connecting");
|
//System.out.println("WebSocket Client connecting");
|
||||||
webSocketClientHandler =
|
webSocketClientHandler =
|
||||||
new WebSocketClientHandler(
|
new WebSocketClientHandler(
|
||||||
WebSocketClientHandshakerFactory.newHandshaker(
|
WebSocketClientHandshakerFactory.newHandshaker(
|
||||||
uri, WebSocketVersion.V13, null, false, EmptyHttpHeaders.INSTANCE, 12800000), this);
|
uri, WebSocketVersion.V13, null, false, EmptyHttpHeaders.INSTANCE, 12800000), this);
|
||||||
ChannelFuture future = bootstrap.connect(uri.getHost(), port);
|
ChannelFuture future = bootstrap.connect(uri.getHost(), port);
|
||||||
future.addListener((e) -> {
|
future.addListener((l) -> {
|
||||||
ch = future.channel();
|
if(l.isSuccess()) {
|
||||||
webSocketClientHandler.handshakeFuture().addListener((e1) -> onConnect.run());
|
ch = future.channel();
|
||||||
|
webSocketClientHandler.handshakeFuture().addListener((e) -> {
|
||||||
|
if(e.isSuccess()) {
|
||||||
|
onConnect.run();
|
||||||
|
} else {
|
||||||
|
onFail.accept(webSocketClientHandler.handshakeFuture().cause());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onFail.accept(future.cause());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
public abstract class ClientWebSocketService extends ClientJSONPoint {
|
public abstract class ClientWebSocketService extends ClientJSONPoint {
|
||||||
public static final ProviderMap<WebSocketEvent> results = new ProviderMap<>();
|
public static final ProviderMap<WebSocketEvent> results = new ProviderMap<>();
|
||||||
public static final ProviderMap<WebSocketRequest> requests = new ProviderMap<>();
|
public static final ProviderMap<WebSocketRequest> requests = new ProviderMap<>();
|
||||||
|
private static boolean resultsRegistered = false;
|
||||||
public final Gson gson;
|
public final Gson gson;
|
||||||
public final Boolean onConnect;
|
public final Boolean onConnect;
|
||||||
public OnCloseCallback onCloseCallback;
|
public OnCloseCallback onCloseCallback;
|
||||||
|
@ -83,38 +84,41 @@ public void registerRequests() {
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public void registerResults() {
|
public void registerResults() {
|
||||||
results.register("auth", AuthRequestEvent.class);
|
if(!resultsRegistered) {
|
||||||
results.register("checkServer", CheckServerRequestEvent.class);
|
results.register("auth", AuthRequestEvent.class);
|
||||||
results.register("joinServer", JoinServerRequestEvent.class);
|
results.register("checkServer", CheckServerRequestEvent.class);
|
||||||
results.register("launcher", LauncherRequestEvent.class);
|
results.register("joinServer", JoinServerRequestEvent.class);
|
||||||
results.register("profileByUsername", ProfileByUsernameRequestEvent.class);
|
results.register("launcher", LauncherRequestEvent.class);
|
||||||
results.register("profileByUUID", ProfileByUUIDRequestEvent.class);
|
results.register("profileByUsername", ProfileByUsernameRequestEvent.class);
|
||||||
results.register("batchProfileByUsername", BatchProfileByUsernameRequestEvent.class);
|
results.register("profileByUUID", ProfileByUUIDRequestEvent.class);
|
||||||
results.register("profiles", ProfilesRequestEvent.class);
|
results.register("batchProfileByUsername", BatchProfileByUsernameRequestEvent.class);
|
||||||
results.register("setProfile", SetProfileRequestEvent.class);
|
results.register("profiles", ProfilesRequestEvent.class);
|
||||||
results.register("updateList", UpdateListRequestEvent.class);
|
results.register("setProfile", SetProfileRequestEvent.class);
|
||||||
results.register("error", ErrorRequestEvent.class);
|
results.register("updateList", UpdateListRequestEvent.class);
|
||||||
results.register("update", UpdateRequestEvent.class);
|
results.register("error", ErrorRequestEvent.class);
|
||||||
results.register("restoreSession", RestoreSessionRequestEvent.class);
|
results.register("update", UpdateRequestEvent.class);
|
||||||
results.register("log", LogEvent.class);
|
results.register("restoreSession", RestoreSessionRequestEvent.class);
|
||||||
results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class);
|
results.register("log", LogEvent.class);
|
||||||
results.register("exception", ExceptionEvent.class);
|
results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class);
|
||||||
results.register("register", RegisterRequestEvent.class);
|
results.register("exception", ExceptionEvent.class);
|
||||||
results.register("notification", NotificationEvent.class);
|
results.register("register", RegisterRequestEvent.class);
|
||||||
results.register("signal", SignalEvent.class);
|
results.register("notification", NotificationEvent.class);
|
||||||
results.register("exit", ExitRequestEvent.class);
|
results.register("signal", SignalEvent.class);
|
||||||
results.register("getSecureLevelInfo", GetSecureLevelInfoRequestEvent.class);
|
results.register("exit", ExitRequestEvent.class);
|
||||||
results.register("verifySecureLevelKey", VerifySecureLevelKeyRequestEvent.class);
|
results.register("getSecureLevelInfo", GetSecureLevelInfoRequestEvent.class);
|
||||||
results.register("securityReport", SecurityReportRequestEvent.class);
|
results.register("verifySecureLevelKey", VerifySecureLevelKeyRequestEvent.class);
|
||||||
results.register("hardwareReport", HardwareReportRequestEvent.class);
|
results.register("securityReport", SecurityReportRequestEvent.class);
|
||||||
results.register("serverStatus", ServerStatusRequestEvent.class);
|
results.register("hardwareReport", HardwareReportRequestEvent.class);
|
||||||
results.register("pingServerReport", PingServerReportRequestEvent.class);
|
results.register("serverStatus", ServerStatusRequestEvent.class);
|
||||||
results.register("pingServer", PingServerRequestEvent.class);
|
results.register("pingServerReport", PingServerReportRequestEvent.class);
|
||||||
results.register("currentUser", CurrentUserRequestEvent.class);
|
results.register("pingServer", PingServerRequestEvent.class);
|
||||||
results.register("features", FeaturesRequestEvent.class);
|
results.register("currentUser", CurrentUserRequestEvent.class);
|
||||||
results.register("refreshToken", RefreshTokenRequestEvent.class);
|
results.register("features", FeaturesRequestEvent.class);
|
||||||
results.register("restore", RestoreRequestEvent.class);
|
results.register("refreshToken", RefreshTokenRequestEvent.class);
|
||||||
results.register("additionalData", AdditionalDataRequestEvent.class);
|
results.register("restore", RestoreRequestEvent.class);
|
||||||
|
results.register("additionalData", AdditionalDataRequestEvent.class);
|
||||||
|
resultsRegistered = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitIfNotConnected() {
|
public void waitIfNotConnected() {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ public StdWebSocketService(String address) throws SSLException {
|
||||||
super(address);
|
super(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StdWebSocketService initWebSockets(String address, boolean async) {
|
public static CompletableFuture<StdWebSocketService> initWebSockets(String address) throws Exception {
|
||||||
StdWebSocketService service;
|
StdWebSocketService service;
|
||||||
try {
|
try {
|
||||||
service = new StdWebSocketService(address);
|
service = new StdWebSocketService(address);
|
||||||
|
@ -37,28 +37,26 @@ public static StdWebSocketService initWebSockets(String address, boolean async)
|
||||||
}
|
}
|
||||||
service.registerResults();
|
service.registerResults();
|
||||||
service.registerRequests();
|
service.registerRequests();
|
||||||
if (!async) {
|
CompletableFuture<StdWebSocketService> future = new CompletableFuture<>();
|
||||||
try {
|
service.openAsync(() -> {
|
||||||
service.open();
|
future.complete(service);
|
||||||
} catch (Exception e) {
|
JVMHelper.RUNTIME.addShutdownHook(new Thread(() -> {
|
||||||
LogHelper.error(e);
|
try {
|
||||||
}
|
//if(service.isOpen())
|
||||||
} else {
|
// service.closeBlocking();
|
||||||
service.openAsync(() -> {
|
service.close();
|
||||||
});
|
} catch (InterruptedException e) {
|
||||||
}
|
LogHelper.error(e);
|
||||||
JVMHelper.RUNTIME.addShutdownHook(new Thread(() -> {
|
}
|
||||||
try {
|
}));
|
||||||
//if(service.isOpen())
|
}, (error) -> {
|
||||||
// service.closeBlocking();
|
future.completeExceptionally(error);
|
||||||
service.close();
|
});
|
||||||
} catch (InterruptedException e) {
|
return future;
|
||||||
LogHelper.error(e);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
return service;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void registerEventHandler(ClientWebSocketService.EventHandler handler) {
|
public void registerEventHandler(ClientWebSocketService.EventHandler handler) {
|
||||||
legacyEventHandlers.add(handler);
|
legacyEventHandlers.add(handler);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,17 +77,15 @@ else if (frame instanceof BinaryWebSocketFrame) {
|
||||||
// uncomment to print request
|
// uncomment to print request
|
||||||
// logger.info(frame.content().toString());
|
// logger.info(frame.content().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
|
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
|
||||||
LogHelper.error(cause);
|
|
||||||
|
|
||||||
if (!handshakeFuture.isDone()) {
|
if (!handshakeFuture.isDone()) {
|
||||||
handshakeFuture.setFailure(cause);
|
handshakeFuture.setFailure(cause);
|
||||||
|
} else {
|
||||||
|
LogHelper.error(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.close();
|
ctx.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -113,7 +113,7 @@ public void run(String... args) throws Throwable {
|
||||||
updateLauncherConfig();
|
updateLauncherConfig();
|
||||||
if (config.env != null) Launcher.applyLauncherEnv(config.env);
|
if (config.env != null) Launcher.applyLauncherEnv(config.env);
|
||||||
else Launcher.applyLauncherEnv(LauncherConfig.LauncherEnvironment.STD);
|
else Launcher.applyLauncherEnv(LauncherConfig.LauncherEnvironment.STD);
|
||||||
StdWebSocketService service = StdWebSocketService.initWebSockets(config.address, false);
|
StdWebSocketService service = StdWebSocketService.initWebSockets(config.address).get();
|
||||||
service.reconnectCallback = () ->
|
service.reconnectCallback = () ->
|
||||||
{
|
{
|
||||||
LogHelper.debug("WebSocket connect closed. Try reconnect");
|
LogHelper.debug("WebSocket connect closed. Try reconnect");
|
||||||
|
|
|
@ -61,7 +61,13 @@ public void run() throws Exception {
|
||||||
if(!Request.isAvailable() || Request.getRequestService().isClosed()) {
|
if(!Request.isAvailable() || Request.getRequestService().isClosed()) {
|
||||||
System.out.println("Print launchserver websocket host( ws://host:port/api ):");
|
System.out.println("Print launchserver websocket host( ws://host:port/api ):");
|
||||||
wrapper.config.address = commands.commandHandler.readLine();
|
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);
|
Request.setRequestService(service);
|
||||||
}
|
}
|
||||||
System.out.println("Print server token:");
|
System.out.println("Print server token:");
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
id 'org.openjfx.javafxplugin' version '0.0.10' apply false
|
id 'org.openjfx.javafxplugin' version '0.0.10' apply false
|
||||||
}
|
}
|
||||||
group = 'pro.gravit.launcher'
|
group = 'pro.gravit.launcher'
|
||||||
version = '5.2.5'
|
version = '5.2.6-SNAPSHOT'
|
||||||
|
|
||||||
apply from: 'props.gradle'
|
apply from: 'props.gradle'
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue