diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index eaa40fb1..e4f23832 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -139,7 +139,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La // build hooks, anti-brutforce and other proguardConf = new ProguardConf(this); - sessionManager = new SessionManager(); + sessionManager = new SessionManager(this); mirrorManager = new MirrorManager(); reconfigurableManager = new ReconfigurableManager(); authHookManager = new AuthHookManager(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/RequiredDAO.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/RequiredDAO.java new file mode 100644 index 00000000..b543e653 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/RequiredDAO.java @@ -0,0 +1,4 @@ +package pro.gravit.launchserver.auth; + +public interface RequiredDAO { +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java index 05cd046c..7e7b3c65 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/provider/HibernateAuthProvider.java @@ -3,11 +3,12 @@ import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.auth.RequiredDAO; import pro.gravit.launchserver.dao.User; import pro.gravit.launchserver.manangers.hook.AuthHookManager; import pro.gravit.utils.helper.SecurityHelper; -public class HibernateAuthProvider extends AuthProvider { +public class HibernateAuthProvider extends AuthProvider implements RequiredDAO { public boolean autoReg; @Override 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 268e9196..163e41c4 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java @@ -1,63 +1,101 @@ package pro.gravit.launchserver.manangers; +import pro.gravit.launcher.Launcher; import pro.gravit.launcher.NeedGarbageCollection; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.RequiredDAO; import pro.gravit.launchserver.socket.Client; +import pro.gravit.utils.helper.LogHelper; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Collectors; public class SessionManager implements NeedGarbageCollection { public static final long SESSION_TIMEOUT = 3 * 60 * 60 * 1000; // 3 часа - private final Map clientSet = new HashMap<>(128); + private final Map clientSet = new ConcurrentHashMap<>(128); + private final LaunchServer server; + + public SessionManager(LaunchServer server) { + this.server = server; + } public boolean addClient(Client client) { - clientSet.put(client.session, client); + if(client == null) return false; + clientSet.put(client.session, new Entry(compressClient(client))); return true; } + private String compressClient(Client client) { + return Launcher.gsonManager.gson.toJson(client); //Compress using later + } + + private Client decompressClient(String client) { + return Launcher.gsonManager.gson.fromJson(client, Client.class); //Compress using later + } + private Client restoreFromString(String data) { + Client result = decompressClient(data); + result.updateAuth(server); + if(result.auth != null && (result.username != null)) { + if(result.auth.handler instanceof RequiredDAO || result.auth.provider instanceof RequiredDAO || result.auth.textureProvider instanceof RequiredDAO) { + result.daoObject = server.config.dao.userDAO.findByUsername(result.username); + } + } + + return result; + } + @Override public void garbageCollection() { long time = System.currentTimeMillis(); clientSet.entrySet().removeIf(entry -> { - Client c = entry.getValue(); - return (c.timestamp + SESSION_TIMEOUT < time); + long timestamp = entry.getValue().timestamp; + return (timestamp + SESSION_TIMEOUT < time); }); } public Client getClient(UUID session) { - return clientSet.get(session); + Entry e = clientSet.get(session); + if(e == null) return null; + return restoreFromString(e.data); } public Client getOrNewClient(UUID session) { - return clientSet.computeIfAbsent(session, Client::new); + Client client = getClient(session); + return client == null ? new Client(session) : client; } - public Client removeClient(UUID session) { - return clientSet.remove(session); + public void removeClient(UUID session) { + clientSet.remove(session); } public void updateClient(UUID session) { - Client c = clientSet.get(session); - if (c != null) { - c.up(); - return; - } - Client newClient = new Client(session); - clientSet.put(session, newClient); + LogHelper.warning("Using deprecated method: sessionManager.updateClient"); } public Set getSessions() { // TODO: removeme - return new HashSet<>(clientSet.values()); + LogHelper.warning("Using deprecated method: sessionManager.getSession"); + return new HashSet<>(); } public void loadSessions(Set set) { - clientSet.putAll(set.stream().collect(Collectors.toMap(c -> c.session, Function.identity()))); + 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 long timestamp; + + public Entry(String data) { + this.data = data; + 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 1b5639d5..441ef732 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java @@ -11,6 +11,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; public class Client { public UUID session; @@ -30,6 +31,8 @@ public class Client { public transient Map properties; + public transient AtomicInteger refCount = new AtomicInteger(1); + public Client(UUID session) { this.session = session; timestamp = System.currentTimeMillis(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java index b8948f25..4406b39f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java @@ -37,7 +37,9 @@ public Client getClient() { } public void setClient(Client client) { + if(this.client != null) this.client.refCount.decrementAndGet(); this.client = client; + if(client != null) client.refCount.incrementAndGet(); } public final UUID getConnectUUID() { @@ -85,6 +87,7 @@ protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) { } else if ((frame instanceof PongWebSocketFrame)) { LogHelper.dev("WebSocket Client received pong"); } else if ((frame instanceof CloseWebSocketFrame)) { + int statusCode = ((CloseWebSocketFrame) frame).statusCode(); ctx.channel().close(); } else { String message = "unsupported frame type: " + frame.getClass().getName(); @@ -95,6 +98,18 @@ protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) { @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (future != null) future.cancel(true); + if(LogHelper.isDevEnabled()) { + LogHelper.dev("Client %s disconnected", IOHelper.getIP(ctx.channel().remoteAddress())); + } + int refCount = client.refCount.decrementAndGet(); + if(client.session != null) { + if(refCount == 0) { + srv.sessionManager.addClient(client); + } + else if(refCount < 0) { + LogHelper.warning("Client session %s reference counter invalid - %d", client.session, refCount); + } + } super.channelInactive(ctx); } } 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 6465617a..d3dab518 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 @@ -100,7 +100,7 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti if (getSession) { if (clientData.session == null) { clientData.session = UUID.randomUUID(); - server.sessionManager.addClient(clientData); + //server.sessionManager.addClient(clientData); } result.session = clientData.session; } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java index f68aefb6..aed2765c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java @@ -21,15 +21,28 @@ public String getType() { @Override public void execute(ChannelHandlerContext ctx, Client client) throws Exception { - Client rClient = server.sessionManager.getClient(session); - if (rClient == null) { + if(session == null) { + sendError("Session invalid"); + return; + } + final Client[] rClient = {null}; + service.forEachActiveChannels((channel, handler) -> { + Client c = handler.getClient(); + if(c != null && session.equals(c.session)) { + rClient[0] = c; + } + }); + if(rClient[0] == null) { + rClient[0] = server.sessionManager.getClient(session); + } + if (rClient[0] == null) { sendError("Session invalid"); return; } WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class); - frameHandler.setClient(rClient); + frameHandler.setClient(rClient[0]); if (needUserInfo) { - sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient))); + sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient[0]))); } else { sendResult(new RestoreSessionRequestEvent()); }