From c596c30ff61c431fd569d24f877c0cadf29f9662 Mon Sep 17 00:00:00 2001 From: Gravita Date: Tue, 15 Dec 2020 19:27:38 +0700 Subject: [PATCH] [ANY] New Sessions system completed --- .../pro/gravit/launchserver/LaunchServer.java | 6 +- .../auth/session/MemorySessionStorage.java | 108 ++++++++++++++++++ .../auth/session/SessionStorage.java | 26 +++++ .../command/dump/DumpSessionsCommand.java | 67 ----------- .../command/handler/CommandHandler.java | 7 -- .../command/service/ServerStatusCommand.java | 2 +- .../config/LaunchServerConfig.java | 18 +-- .../manangers/LaunchServerGsonManager.java | 2 + .../manangers/SessionManager.java | 91 +++------------ modules | 2 +- 10 files changed, 171 insertions(+), 158 deletions(-) create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/MemorySessionStorage.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/SessionStorage.java delete mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/command/dump/DumpSessionsCommand.java diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index e4f23832..2a7d58b8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -10,6 +10,7 @@ import pro.gravit.launcher.modules.events.ClosePhase; import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launchserver.auth.AuthProviderPair; +import pro.gravit.launchserver.auth.session.MemorySessionStorage; import pro.gravit.launchserver.binary.*; import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; @@ -128,6 +129,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La runtime.verify(); config.verify(); + if(config.sessions == null) config.sessions = new MemorySessionStorage(); if (config.components != null) { LogHelper.debug("PreInit components"); config.components.forEach((k, v) -> { @@ -147,7 +149,8 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La pingServerManager = new PingServerManager(this); //Generate or set new Certificate API certificateManager.orgName = config.projectName; - if (config.certificate != null && config.certificate.enabled) { + /* + if (false) { if (IOHelper.isFile(caCertFile) && IOHelper.isFile(caKeyFile)) { certificateManager.ca = certificateManager.readCertificate(caCertFile); certificateManager.caKey = certificateManager.readPrivateKey(caKeyFile); @@ -175,6 +178,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La } } } + */ config.init(ReloadType.FULL); registerObject("launchServer", this); GarbageManager.registerNeedGC(sessionManager); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/MemorySessionStorage.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/MemorySessionStorage.java new file mode 100644 index 00000000..bb1043d9 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/MemorySessionStorage.java @@ -0,0 +1,108 @@ +package pro.gravit.launchserver.auth.session; + +import pro.gravit.launcher.NeedGarbageCollection; +import pro.gravit.launchserver.manangers.SessionManager; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +public class MemorySessionStorage extends SessionStorage implements NeedGarbageCollection { + + private final Map clientSet = new ConcurrentHashMap<>(128); + private final Map> uuidIndex = new ConcurrentHashMap<>(32); + + @Override + public byte[] getSessionData(UUID session) { + + Entry e = clientSet.get(session); + if(e == null) return null; + return e.data; + } + + @Override + public Stream getSessionsFromUserUUID(UUID userUUID) { + Set set = uuidIndex.get(userUUID); + if(set != null) return set.stream().map((e) -> e.sessionUuid); + return null; + } + + @Override + public boolean writeSession(UUID userUUID, UUID sessionUUID, byte[] data) { + deleteSession(sessionUUID); + Entry e = new Entry(data, sessionUUID); + clientSet.put(sessionUUID, e); + if(userUUID != null) { + Set uuidSet = uuidIndex.computeIfAbsent(userUUID, k -> ConcurrentHashMap.newKeySet()); + uuidSet.add(e); + } + return false; + } + + @Override + public boolean deleteSession(UUID sessionUUID) { + Entry e =clientSet.remove(sessionUUID); + if(e != null) { + Set set = uuidIndex.get(sessionUUID); + if(set != null) { + removeUuidFromIndexSet(set, e, sessionUUID); + } + return true; + } + return false; + } + + @Override + public boolean deleteSessionsByUserUUID(UUID userUUID) { + Set set = uuidIndex.get(userUUID); + if(set != null) { + for(Entry e : set) { + clientSet.remove(e.sessionUuid); + } + set.clear(); + uuidIndex.remove(userUUID); + } + return true; + } + + @Override + public void clear() { + clientSet.clear(); + uuidIndex.clear(); + } + + private void removeUuidFromIndexSet(Set set, Entry e, UUID session) { + set.remove(e); + if(set.isEmpty()) { + uuidIndex.remove(session); + } + } + + @Override + public void garbageCollection() { + long time = System.currentTimeMillis(); + long session_timeout = server.config.netty.performance.sessionLifetimeMs; + Set to_delete = new HashSet<>(32); + clientSet.forEach((uuid, entry) -> { + long timestamp = entry.timestamp; + if(timestamp + session_timeout < time) + to_delete.add(uuid); + }); + for(UUID session : to_delete) { + deleteSession(session); + } + to_delete.clear(); + } + + private static class Entry { + public byte[] data; + public UUID sessionUuid; + public long timestamp; + + public Entry(byte[] data, UUID sessionUuid) { + this.data = data; + this.sessionUuid = sessionUuid; + this.timestamp = System.currentTimeMillis(); + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/SessionStorage.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/SessionStorage.java new file mode 100644 index 00000000..463b7a60 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/SessionStorage.java @@ -0,0 +1,26 @@ +package pro.gravit.launchserver.auth.session; + +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.utils.ProviderMap; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Stream; + +public abstract class SessionStorage { + protected transient LaunchServer server; + public static ProviderMap providers = new ProviderMap<>(); + public abstract byte[] getSessionData(UUID session); + public abstract Stream getSessionsFromUserUUID(UUID userUUID); + public abstract boolean writeSession(UUID userUUID, UUID sessionUUID, byte[] data); + public abstract boolean deleteSession(UUID sessionUUID); + public boolean deleteSessionsByUserUUID(UUID userUUID) { + getSessionsFromUserUUID(userUUID).forEach(this::deleteSession); + return true; + } + public abstract void clear(); + public void init(LaunchServer server) + { + this.server = server; + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/dump/DumpSessionsCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/dump/DumpSessionsCommand.java deleted file mode 100644 index 4eff81ff..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/dump/DumpSessionsCommand.java +++ /dev/null @@ -1,67 +0,0 @@ -package pro.gravit.launchserver.command.dump; - -import com.google.gson.reflect.TypeToken; -import pro.gravit.launcher.Launcher; -import pro.gravit.launchserver.LaunchServer; -import pro.gravit.launchserver.command.Command; -import pro.gravit.launchserver.socket.Client; -import pro.gravit.utils.command.SubCommand; -import pro.gravit.utils.helper.IOHelper; -import pro.gravit.utils.helper.LogHelper; - -import java.io.Reader; -import java.io.Writer; -import java.lang.reflect.Type; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -public class DumpSessionsCommand extends Command { - public DumpSessionsCommand(LaunchServer server) { - super(server); - childCommands.put("load", new SubCommand() { - @Override - public void invoke(String... args) throws Exception { - verifyArgs(args, 1); - LogHelper.info("Sessions read from %s", args[0]); - int size; - try (Reader reader = IOHelper.newReader(Paths.get(args[0]))) { - Type setType = new TypeToken>() { - }.getType(); - Set clientSet = Launcher.gsonManager.configGson.fromJson(reader, setType); - size = clientSet.size(); - server.sessionManager.loadSessions(clientSet); - } - LogHelper.subInfo("Readed %d sessions", size); - } - }); - childCommands.put("unload", new SubCommand() { - @Override - public void invoke(String... args) throws Exception { - verifyArgs(args, 1); - LogHelper.info("Sessions write to %s", args[0]); - Collection clientSet = server.sessionManager.getSessions(); - try (Writer writer = IOHelper.newWriter(Paths.get(args[0]))) { - Launcher.gsonManager.configGson.toJson(clientSet, writer); - } - LogHelper.subInfo("Write %d sessions", clientSet.size()); - } - }); - } - - @Override - public String getArgsDescription() { - return "[load/unload] [filename]"; - } - - @Override - public String getUsageDescription() { - return "Load or unload sessions"; - } - - @Override - public void invoke(String... args) throws Exception { - invokeSubcommands(args); - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/handler/CommandHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/handler/CommandHandler.java index cbda2b48..d001f466 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/handler/CommandHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/handler/CommandHandler.java @@ -5,7 +5,6 @@ import pro.gravit.launchserver.command.auth.UUIDToUsernameCommand; import pro.gravit.launchserver.command.auth.UsernameToUUIDCommand; import pro.gravit.launchserver.command.basic.*; -import pro.gravit.launchserver.command.dump.DumpSessionsCommand; import pro.gravit.launchserver.command.hash.*; import pro.gravit.launchserver.command.install.CheckInstallCommand; import pro.gravit.launchserver.command.install.MultiCommand; @@ -61,12 +60,6 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand Category authCategory = new Category(auth, "auth", "User Management"); handler.registerCategory(authCategory); - //Register dump commands - BaseCommandCategory dump = new BaseCommandCategory(); - dump.registerCommand("dumpSessions", new DumpSessionsCommand(server)); - Category dumpCategory = new Category(dump, "dump", "Dump runtime data"); - handler.registerCategory(dumpCategory); - //Register service commands BaseCommandCategory service = new BaseCommandCategory(); service.registerCommand("config", new ConfigCommand(server)); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java index f7c1b9cd..bc0aef04 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java @@ -38,7 +38,7 @@ public void invoke(String... args) { for (CommandHandler.Category category : server.commandHandler.getCategories()) { commands += category.category.commandsMap().size(); } - LogHelper.info("Sessions: %d | Commands: %d(%d categories)", server.sessionManager.getSessions().size(), commands, server.commandHandler.getCategories().size() + 1); + LogHelper.info("Commands: %d(%d categories)", commands, server.commandHandler.getCategories().size() + 1); for (AuthProviderPair pair : server.config.auth.values()) { if (pair.handler instanceof CachedAuthHandler) { LogHelper.info("AuthHandler %s: EntryCache: %d | usernameCache: %d", pair.name, ((CachedAuthHandler) pair.handler).getEntryCache().size(), ((CachedAuthHandler) pair.handler).getUsernamesCache().size()); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java index 8bd46f99..170cc4c4 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -10,6 +10,8 @@ import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.StdProtectHandler; import pro.gravit.launchserver.auth.provider.RejectAuthProvider; +import pro.gravit.launchserver.auth.session.MemorySessionStorage; +import pro.gravit.launchserver.auth.session.SessionStorage; import pro.gravit.launchserver.auth.texture.RequestTextureProvider; import pro.gravit.launchserver.binary.tasks.exe.Launch4JTask; import pro.gravit.launchserver.components.AuthLimiterComponent; @@ -33,6 +35,7 @@ public final class LaunchServerConfig { public LauncherConfig.LauncherEnvironment env; public Map auth; public DaoProvider dao; + public SessionStorage sessions; // Handlers & Providers public ProtectHandler protectHandler; @@ -40,7 +43,6 @@ public final class LaunchServerConfig { public ExeConf launch4j; public NettyConfig netty; public LauncherConf launcher; - public CertificateConf certificate; public JarSignerConf sign; public String startScript; private transient LaunchServer server = null; @@ -71,6 +73,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { a.displayName = "Default"; newConfig.auth.put("std", a); newConfig.protectHandler = new StdProtectHandler(); + newConfig.sessions = new MemorySessionStorage(); newConfig.binaryName = "Launcher"; newConfig.netty = new NettyConfig(); @@ -97,8 +100,6 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { newConfig.launcher.stripLineNumbers = true; newConfig.launcher.proguardGenMappings = true; - newConfig.certificate = new LaunchServerConfig.CertificateConf(); - newConfig.certificate.enabled = false; newConfig.sign = new JarSignerConf(); newConfig.components = new HashMap<>(); @@ -187,6 +188,10 @@ public void init(LaunchServer.ReloadType type) { protectHandler.init(server); protectHandler.checkLaunchServerLicense(); } + if(sessions != null) { + sessions.init(server); + server.registerObject("sessions", sessions); + } if (components != null) { components.forEach((k, v) -> server.registerObject("component.".concat(k), v)); } @@ -229,6 +234,9 @@ public void close(LaunchServer.ReloadType type) { server.unregisterObject("protectHandler", protectHandler); protectHandler.close(); } + if(sessions != null) { + server.unregisterObject("sessions", sessions); + } if (dao != null) { server.unregisterObject("dao", dao); if (dao instanceof AutoCloseable) { @@ -260,10 +268,6 @@ public static class ExeConf { public String txtProductVersion; } - public static class CertificateConf { - public boolean enabled; - } - public static class JarSignerConf { public boolean enabled = false; public String keyStore = "pathToKey"; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java index b4d3d9c8..1cdf41e1 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java @@ -11,6 +11,7 @@ import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider; import pro.gravit.launchserver.auth.provider.AuthProvider; +import pro.gravit.launchserver.auth.session.SessionStorage; import pro.gravit.launchserver.auth.texture.TextureProvider; import pro.gravit.launchserver.components.Component; import pro.gravit.launchserver.dao.provider.DaoProvider; @@ -41,6 +42,7 @@ public void registerAdapters(GsonBuilder builder) { builder.registerTypeAdapter(AuthRequest.AuthPasswordInterface.class, new UniversalJsonAdapter<>(AuthRequest.providers)); builder.registerTypeAdapter(HWIDProvider.class, new UniversalJsonAdapter<>(HWIDProvider.providers)); builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers)); + builder.registerTypeAdapter(SessionStorage.class, new UniversalJsonAdapter<>(SessionStorage.providers)); modulesManager.invokeEvent(new PreGsonPhase(builder)); //ClientWebSocketService.appendTypeAdapters(builder); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java index fd14780c..d6066868 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java @@ -8,6 +8,7 @@ import pro.gravit.utils.HookSet; import pro.gravit.utils.helper.LogHelper; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -15,8 +16,6 @@ public class SessionManager implements NeedGarbageCollection { - private final Map clientSet = new ConcurrentHashMap<>(128); - private final Map> uuidIndex = new ConcurrentHashMap<>(32); private final LaunchServer server; public HookSet clientRestoreHook = new HookSet<>(); @@ -27,52 +26,35 @@ public SessionManager(LaunchServer server) { public boolean addClient(Client client) { if(client == null || client.session == null) return false; - remove(client.session); - Entry e = new Entry(compressClient(client), client.session); - clientSet.put(client.session, e); - if(client.isAuth && client.uuid != null) { - Set uuidSet = uuidIndex.computeIfAbsent(client.uuid, k -> ConcurrentHashMap.newKeySet()); - uuidSet.add(e); - } - return true; + return server.config.sessions.writeSession(client.uuid, client.session, compressClient(client)); } public Stream findSessionsByUUID(UUID uuid) { - Set set = uuidIndex.get(uuid); - if(set != null) return set.stream().map((e) -> e.sessionUuid); - return null; + return server.config.sessions.getSessionsFromUserUUID(uuid); } public boolean removeByUUID(UUID uuid) { - Set set = uuidIndex.get(uuid); - if(set != null) { - for(Entry e : set) { - clientSet.remove(e.sessionUuid); - } - set.clear(); - uuidIndex.remove(uuid); - } - return false; + return server.config.sessions.deleteSessionsByUserUUID(uuid); } + @Deprecated public Set getSavedUUIDs() { - return uuidIndex.keySet(); + throw new UnsupportedOperationException(); } public void clear() { - clientSet.clear(); - uuidIndex.clear(); + server.config.sessions.clear(); } - private String compressClient(Client client) { - return Launcher.gsonManager.gson.toJson(client); //Compress using later + private byte[] compressClient(Client client) { + return Launcher.gsonManager.gson.toJson(client).getBytes(StandardCharsets.UTF_8); //Compress using later } - private Client decompressClient(String client) { - return Launcher.gsonManager.gson.fromJson(client, Client.class); //Compress using later + private Client decompressClient(byte[] client) { + return Launcher.gsonManager.gson.fromJson(new String(client, StandardCharsets.UTF_8), Client.class); //Compress using later } - private Client restoreFromString(String data) { + private Client restoreFromString(byte[] data) { Client result = decompressClient(data); result.updateAuth(server); if(result.auth != null && (result.username != null)) { @@ -87,25 +69,11 @@ private Client restoreFromString(String data) { @Override public void garbageCollection() { - long time = System.currentTimeMillis(); - long session_timeout = server.config.netty.performance.sessionLifetimeMs; - Set to_delete = new HashSet<>(32); - clientSet.forEach((uuid, entry) -> { - long timestamp = entry.timestamp; - if(timestamp + session_timeout < time) - to_delete.add(uuid); - }); - for(UUID session : to_delete) { - remove(session); - } - to_delete.clear(); } public Client getClient(UUID session) { - Entry e = clientSet.get(session); - if(e == null) return null; - return restoreFromString(e.data); + return restoreFromString(server.config.sessions.getSessionData(session)); } @@ -115,52 +83,27 @@ public Client getOrNewClient(UUID session) { } public boolean remove(UUID session) { - Entry e =clientSet.remove(session); - if(e != null) { - Set set = uuidIndex.get(session); - if(set != null) { - removeUuidFromIndexSet(set, e, session); - } - return true; - } - return false; + return server.config.sessions.deleteSession(session); } - private void removeUuidFromIndexSet(Set set, Entry e, UUID session) { - set.remove(e); - if(set.isEmpty()) { - uuidIndex.remove(session); - } - } @Deprecated public void removeClient(UUID session) { remove(session); } - + @Deprecated public void updateClient(UUID session) { LogHelper.warning("Using deprecated method: sessionManager.updateClient"); } + @Deprecated public Set getSessions() { - // TODO: removeme LogHelper.warning("Using deprecated method: sessionManager.getSession"); return new HashSet<>(); } - + @Deprecated public void loadSessions(Set set) { LogHelper.warning("Using deprecated method: sessionManager.loadSessions"); //clientSet.putAll(set.stream().collect(Collectors.toMap(c -> c.session, Function.identity()))); } - private static class Entry { - public String data; - public UUID sessionUuid; - public long timestamp; - - public Entry(String data, UUID sessionUuid) { - this.data = data; - this.sessionUuid = sessionUuid; - this.timestamp = System.currentTimeMillis(); - } - } } diff --git a/modules b/modules index e990b35b..5c4f6850 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit e990b35b4001e29793b383dfa7b179aa0b27b307 +Subproject commit 5c4f6850bd4feeee0caff5561564b7e54bb94774