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 bc450975..3c242394 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -312,6 +312,7 @@ public static class NettyPerformanceConfig { public boolean usingEpoll; public int bossThread; public int workerThread; + public long sessionLifetimeMs = 24 * 60 * 60 * 1000; } public static class NettyBindAddress { 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 8741344a..fd14780c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java @@ -5,19 +5,20 @@ import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.RequiredDAO; import pro.gravit.launchserver.socket.Client; +import pro.gravit.utils.HookSet; import pro.gravit.utils.helper.LogHelper; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; -import java.util.stream.Collectors; +import java.util.stream.Stream; public class SessionManager implements NeedGarbageCollection { - public static final long SESSION_TIMEOUT = 3 * 60 * 60 * 1000; // 3 часа private final Map clientSet = new ConcurrentHashMap<>(128); + private final Map> uuidIndex = new ConcurrentHashMap<>(32); private final LaunchServer server; + public HookSet clientRestoreHook = new HookSet<>(); public SessionManager(LaunchServer server) { this.server = server; @@ -25,11 +26,45 @@ public SessionManager(LaunchServer server) { public boolean addClient(Client client) { - if(client == null) return false; - clientSet.put(client.session, new Entry(compressClient(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; } + public Stream findSessionsByUUID(UUID uuid) { + Set set = uuidIndex.get(uuid); + if(set != null) return set.stream().map((e) -> e.sessionUuid); + return null; + } + + 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; + } + + public Set getSavedUUIDs() + { + return uuidIndex.keySet(); + } + + public void clear() { + clientSet.clear(); + uuidIndex.clear(); + } + private String compressClient(Client client) { return Launcher.gsonManager.gson.toJson(client); //Compress using later } @@ -46,16 +81,24 @@ private Client restoreFromString(String data) { } } if(result.refCount == null) result.refCount = new AtomicInteger(1); + clientRestoreHook.hook(result); return result; } @Override public void garbageCollection() { long time = System.currentTimeMillis(); - clientSet.entrySet().removeIf(entry -> { - long timestamp = entry.getValue().timestamp; - return (timestamp + SESSION_TIMEOUT < time); + 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(); } @@ -71,8 +114,27 @@ public Client getOrNewClient(UUID session) { return client == null ? new Client(session) : client; } + 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; + } + + private void removeUuidFromIndexSet(Set set, Entry e, UUID session) { + set.remove(e); + if(set.isEmpty()) { + uuidIndex.remove(session); + } + } + @Deprecated public void removeClient(UUID session) { - clientSet.remove(session); + remove(session); } @@ -92,10 +154,12 @@ public void loadSessions(Set set) { } private static class Entry { public String data; + public UUID sessionUuid; public long timestamp; - public Entry(String data) { + public Entry(String data, UUID sessionUuid) { this.data = data; + this.sessionUuid = sessionUuid; this.timestamp = System.currentTimeMillis(); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java index 441ef732..57113f14 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java @@ -23,6 +23,7 @@ public class Client { public boolean checkSign; public ClientPermissions permissions; public String username; + public UUID uuid; public TrustLevel trustLevel; public transient AuthProviderPair auth; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java index d3dab518..6fd35b41 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java @@ -104,17 +104,17 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti } result.session = clientData.session; } - UUID uuid; if (authType == ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) { - uuid = pair.handler.auth(aresult); + clientData.uuid = pair.handler.auth(aresult); if (LogHelper.isDebugEnabled()) { - LogHelper.debug("Auth: %s accessToken %s uuid: %s", login, result.accessToken, uuid.toString()); + LogHelper.debug("Auth: %s accessToken %s uuid: %s", login, result.accessToken, clientData.uuid.toString()); } } else { - uuid = pair.handler.usernameToUUID(aresult.username); + clientData.uuid = pair.handler.usernameToUUID(aresult.username); result.accessToken = null; } - result.playerProfile = ProfileByUUIDResponse.getProfile(uuid, aresult.username, client, clientData.auth.textureProvider); + + result.playerProfile = ProfileByUUIDResponse.getProfile(clientData.uuid, aresult.username, client, clientData.auth.textureProvider); clientData.type = authType; sendResult(result); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CurrentUserResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CurrentUserResponse.java index 6d5cfd33..5aa7514c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CurrentUserResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CurrentUserResponse.java @@ -23,7 +23,7 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception { public static CurrentUserRequestEvent.UserInfo collectUserInfoFromClient(Client client) throws IOException { CurrentUserRequestEvent.UserInfo result = new CurrentUserRequestEvent.UserInfo(); if (client.auth != null && client.isAuth && client.username != null) { - UUID uuid = client.auth.handler.usernameToUUID(client.username); + UUID uuid = client.uuid != null ? client.uuid : client.auth.handler.usernameToUUID(client.username); if (uuid != null) { result.playerProfile = ProfileByUUIDResponse.getProfile(uuid, client.username, client.profile == null ? null : client.profile.getTitle(), client.auth.textureProvider); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java index 66d3cec1..1a32823e 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java @@ -38,7 +38,7 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception { Client newClient = new Client(null); newClient.checkSign = client.checkSign; handler.setClient(newClient); - if (client.session != null) server.sessionManager.removeClient(client.session); + if (client.session != null) server.sessionManager.remove(client.session); if (exitAll) { service.forEachActiveChannels(((channel, webSocketFrameHandler) -> { Client client1 = webSocketFrameHandler.getClient(); @@ -68,7 +68,7 @@ public static void exit(LaunchServer server, WebSocketFrameHandler wsHandler, Ch Client newCusClient = new Client(null); newCusClient.checkSign = chClient.checkSign; wsHandler.setClient(newCusClient); - if (chClient.session != null) server.sessionManager.removeClient(chClient.session); + if (chClient.session != null) server.sessionManager.remove(chClient.session); ExitRequestEvent event = new ExitRequestEvent(reason); event.requestUUID = RequestEvent.eventUUID; wsHandler.service.sendObject(channel, event);