mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 11:39:11 +03:00
[FEATURE][EXPERIMENTAL] Работа с сессиями
This commit is contained in:
parent
3a80a74912
commit
18b23b195a
8 changed files with 98 additions and 24 deletions
|
@ -139,7 +139,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
|
|
||||||
// build hooks, anti-brutforce and other
|
// build hooks, anti-brutforce and other
|
||||||
proguardConf = new ProguardConf(this);
|
proguardConf = new ProguardConf(this);
|
||||||
sessionManager = new SessionManager();
|
sessionManager = new SessionManager(this);
|
||||||
mirrorManager = new MirrorManager();
|
mirrorManager = new MirrorManager();
|
||||||
reconfigurableManager = new ReconfigurableManager();
|
reconfigurableManager = new ReconfigurableManager();
|
||||||
authHookManager = new AuthHookManager();
|
authHookManager = new AuthHookManager();
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
package pro.gravit.launchserver.auth;
|
||||||
|
|
||||||
|
public interface RequiredDAO {
|
||||||
|
}
|
|
@ -3,11 +3,12 @@
|
||||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||||
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
||||||
import pro.gravit.launchserver.auth.AuthException;
|
import pro.gravit.launchserver.auth.AuthException;
|
||||||
|
import pro.gravit.launchserver.auth.RequiredDAO;
|
||||||
import pro.gravit.launchserver.dao.User;
|
import pro.gravit.launchserver.dao.User;
|
||||||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
public class HibernateAuthProvider extends AuthProvider {
|
public class HibernateAuthProvider extends AuthProvider implements RequiredDAO {
|
||||||
public boolean autoReg;
|
public boolean autoReg;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,63 +1,101 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launcher.NeedGarbageCollection;
|
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.launchserver.socket.Client;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SessionManager implements NeedGarbageCollection {
|
public class SessionManager implements NeedGarbageCollection {
|
||||||
|
|
||||||
public static final long SESSION_TIMEOUT = 3 * 60 * 60 * 1000; // 3 часа
|
public static final long SESSION_TIMEOUT = 3 * 60 * 60 * 1000; // 3 часа
|
||||||
private final Map<UUID, Client> clientSet = new HashMap<>(128);
|
private final Map<UUID, Entry> clientSet = new ConcurrentHashMap<>(128);
|
||||||
|
private final LaunchServer server;
|
||||||
|
|
||||||
|
public SessionManager(LaunchServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean addClient(Client client) {
|
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;
|
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
|
@Override
|
||||||
public void garbageCollection() {
|
public void garbageCollection() {
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
clientSet.entrySet().removeIf(entry -> {
|
clientSet.entrySet().removeIf(entry -> {
|
||||||
Client c = entry.getValue();
|
long timestamp = entry.getValue().timestamp;
|
||||||
return (c.timestamp + SESSION_TIMEOUT < time);
|
return (timestamp + SESSION_TIMEOUT < time);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Client getClient(UUID session) {
|
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) {
|
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) {
|
public void removeClient(UUID session) {
|
||||||
return clientSet.remove(session);
|
clientSet.remove(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updateClient(UUID session) {
|
public void updateClient(UUID session) {
|
||||||
Client c = clientSet.get(session);
|
LogHelper.warning("Using deprecated method: sessionManager.updateClient");
|
||||||
if (c != null) {
|
|
||||||
c.up();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Client newClient = new Client(session);
|
|
||||||
clientSet.put(session, newClient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Client> getSessions() {
|
public Set<Client> getSessions() {
|
||||||
// TODO: removeme
|
// TODO: removeme
|
||||||
return new HashSet<>(clientSet.values());
|
LogHelper.warning("Using deprecated method: sessionManager.getSession");
|
||||||
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadSessions(Set<Client> set) {
|
public void loadSessions(Set<Client> 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class Client {
|
public class Client {
|
||||||
public UUID session;
|
public UUID session;
|
||||||
|
@ -30,6 +31,8 @@ public class Client {
|
||||||
|
|
||||||
public transient Map<String, Object> properties;
|
public transient Map<String, Object> properties;
|
||||||
|
|
||||||
|
public transient AtomicInteger refCount = new AtomicInteger(1);
|
||||||
|
|
||||||
public Client(UUID session) {
|
public Client(UUID session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
|
|
|
@ -37,7 +37,9 @@ public Client getClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClient(Client client) {
|
public void setClient(Client client) {
|
||||||
|
if(this.client != null) this.client.refCount.decrementAndGet();
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
if(client != null) client.refCount.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final UUID getConnectUUID() {
|
public final UUID getConnectUUID() {
|
||||||
|
@ -85,6 +87,7 @@ protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
||||||
} else if ((frame instanceof PongWebSocketFrame)) {
|
} else if ((frame instanceof PongWebSocketFrame)) {
|
||||||
LogHelper.dev("WebSocket Client received pong");
|
LogHelper.dev("WebSocket Client received pong");
|
||||||
} else if ((frame instanceof CloseWebSocketFrame)) {
|
} else if ((frame instanceof CloseWebSocketFrame)) {
|
||||||
|
int statusCode = ((CloseWebSocketFrame) frame).statusCode();
|
||||||
ctx.channel().close();
|
ctx.channel().close();
|
||||||
} else {
|
} else {
|
||||||
String message = "unsupported frame type: " + frame.getClass().getName();
|
String message = "unsupported frame type: " + frame.getClass().getName();
|
||||||
|
@ -95,6 +98,18 @@ protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
if (future != null) future.cancel(true);
|
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);
|
super.channelInactive(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
|
||||||
if (getSession) {
|
if (getSession) {
|
||||||
if (clientData.session == null) {
|
if (clientData.session == null) {
|
||||||
clientData.session = UUID.randomUUID();
|
clientData.session = UUID.randomUUID();
|
||||||
server.sessionManager.addClient(clientData);
|
//server.sessionManager.addClient(clientData);
|
||||||
}
|
}
|
||||||
result.session = clientData.session;
|
result.session = clientData.session;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,15 +21,28 @@ public String getType() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
Client rClient = server.sessionManager.getClient(session);
|
if(session == null) {
|
||||||
if (rClient == 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");
|
sendError("Session invalid");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class);
|
WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class);
|
||||||
frameHandler.setClient(rClient);
|
frameHandler.setClient(rClient[0]);
|
||||||
if (needUserInfo) {
|
if (needUserInfo) {
|
||||||
sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient)));
|
sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient[0])));
|
||||||
} else {
|
} else {
|
||||||
sendResult(new RestoreSessionRequestEvent());
|
sendResult(new RestoreSessionRequestEvent());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue