[FEATURE] SessionManager: uuidIndex

This commit is contained in:
Gravit 2020-11-21 20:08:39 +07:00
parent 447866d001
commit 0f8f51ea97
No known key found for this signature in database
GPG key ID: 98A079490768CCE5
6 changed files with 84 additions and 18 deletions

View file

@ -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 {

View file

@ -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<UUID, Entry> clientSet = new ConcurrentHashMap<>(128);
private final Map<UUID, Set<Entry>> uuidIndex = new ConcurrentHashMap<>(32);
private final LaunchServer server;
public HookSet<Client> 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<Entry> uuidSet = uuidIndex.computeIfAbsent(client.uuid, k -> ConcurrentHashMap.newKeySet());
uuidSet.add(e);
}
return true;
}
public Stream<UUID> findSessionsByUUID(UUID uuid) {
Set<Entry> set = uuidIndex.get(uuid);
if(set != null) return set.stream().map((e) -> e.sessionUuid);
return null;
}
public boolean removeByUUID(UUID uuid) {
Set<Entry> set = uuidIndex.get(uuid);
if(set != null) {
for(Entry e : set) {
clientSet.remove(e.sessionUuid);
}
set.clear();
uuidIndex.remove(uuid);
}
return false;
}
public Set<UUID> 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<UUID> 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<Entry> set = uuidIndex.get(session);
if(set != null) {
removeUuidFromIndexSet(set, e, session);
}
return true;
}
return false;
}
private void removeUuidFromIndexSet(Set<Entry> 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<Client> 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();
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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);