mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +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
|
||||
proguardConf = new ProguardConf(this);
|
||||
sessionManager = new SessionManager();
|
||||
sessionManager = new SessionManager(this);
|
||||
mirrorManager = new MirrorManager();
|
||||
reconfigurableManager = new ReconfigurableManager();
|
||||
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.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
|
||||
|
|
|
@ -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<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) {
|
||||
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<Client> getSessions() {
|
||||
// TODO: removeme
|
||||
return new HashSet<>(clientSet.values());
|
||||
LogHelper.warning("Using deprecated method: sessionManager.getSession");
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
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.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<String, Object> properties;
|
||||
|
||||
public transient AtomicInteger refCount = new AtomicInteger(1);
|
||||
|
||||
public Client(UUID session) {
|
||||
this.session = session;
|
||||
timestamp = System.currentTimeMillis();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue