Исправил баг что пир повторном подключении по одной сессии всё будет норм работать
This commit is contained in:
AidarKC 2025-12-26 13:12:53 +03:00
parent eeb8ee9069
commit 809d897da6
3 changed files with 62 additions and 39 deletions

View File

@ -1,26 +1,19 @@
package server.logic.ws_protocol.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Реестр активных подключений (только авторизованные).
*
* Позволяет:
* - получить ConnectionContext по sessionId;
* - получить все активные подключения пользователя по login;
* - удалить подключение при закрытии WebSocket.
*
* найти все подключения пользователя:
* var set = ActiveConnectionsRegistry.getInstance().getByLoginId(loginId);
*
* найти конкретное подключение по sessionId:
* ConnectionContext ctx = ActiveConnectionsRegistry.getInstance().getBySessionId(sessionId);
* Session ws = ctx != null ? ctx.getWsSession() : null;
*/
public final class ActiveConnectionsRegistry {
private static final Logger log = LoggerFactory.getLogger(ActiveConnectionsRegistry.class);
private static final ActiveConnectionsRegistry INSTANCE = new ActiveConnectionsRegistry();
public static ActiveConnectionsRegistry getInstance() {
@ -47,15 +40,33 @@ public final class ActiveConnectionsRegistry {
String sessionId = ctx.getSessionId();
String login = ctx.getLogin();
if (sessionId == null || login == null || login.isBlank()) {
if (sessionId == null || sessionId.isBlank() || login == null || login.isBlank()) {
log.debug("register skipped: bad ctx fields (login='{}', sessionId='{}')", login, sessionId);
return;
}
bySessionId.put(sessionId, ctx);
// Если кто-то перерегистрировал тот же sessionId вычищаем старый ctx из byLogin
ConnectionContext prev = bySessionId.put(sessionId, ctx);
if (prev != null && prev != ctx) {
String prevLogin = prev.getLogin();
if (prevLogin != null && !prevLogin.isBlank()) {
Set<ConnectionContext> prevSet = byLogin.get(prevLogin);
if (prevSet != null) {
prevSet.remove(prev);
if (prevSet.isEmpty()) {
byLogin.remove(prevLogin);
}
}
}
log.warn("sessionId reused: replaced previous ctx (sessionId={}, prevLogin={}, newLogin={})",
sessionId, prevLogin, login);
}
byLogin
.computeIfAbsent(login, id -> new CopyOnWriteArraySet<>())
.add(ctx);
log.debug("registered ctx (login={}, sessionId={})", login, sessionId);
}
/**
@ -67,11 +78,17 @@ public final class ActiveConnectionsRegistry {
String sessionId = ctx.getSessionId();
String login = ctx.getLogin();
if (sessionId != null) {
bySessionId.remove(sessionId);
if (sessionId != null && !sessionId.isBlank()) {
ConnectionContext removed = bySessionId.remove(sessionId);
// Если в мапе лежал другой ctx под тем же sessionId не трогаем его byLogin
if (removed != null && removed != ctx) {
log.debug("remove(ctx): sessionId mapped to another ctx, skip byLogin cleanup (sessionId={})", sessionId);
return;
}
}
if (login != null) {
if (login != null && !login.isBlank()) {
Set<ConnectionContext> set = byLogin.get(login);
if (set != null) {
set.remove(ctx);
@ -80,34 +97,38 @@ public final class ActiveConnectionsRegistry {
}
}
}
log.debug("removed ctx (login={}, sessionId={})", login, sessionId);
}
/**
* Удалить подключение по sessionId.
*/
public void removeBySessionId(String sessionId) {
if (sessionId == null) return;
if (sessionId == null || sessionId.isBlank()) return;
ConnectionContext ctx = bySessionId.remove(sessionId);
if (ctx != null) {
String login = ctx.getLogin();
if (login != null) {
Set<ConnectionContext> set = byLogin.get(login);
if (set != null) {
set.remove(ctx);
if (set.isEmpty()) {
byLogin.remove(login);
}
if (ctx == null) return;
String login = ctx.getLogin();
if (login != null && !login.isBlank()) {
Set<ConnectionContext> set = byLogin.get(login);
if (set != null) {
set.remove(ctx);
if (set.isEmpty()) {
byLogin.remove(login);
}
}
}
log.debug("removed by sessionId (login={}, sessionId={})", login, sessionId);
}
/**
* Получить контекст по sessionId.
*/
public ConnectionContext getBySessionId(String sessionId) {
if (sessionId == null) return null;
if (sessionId == null || sessionId.isBlank()) return null;
return bySessionId.get(sessionId);
}
@ -115,12 +136,8 @@ public final class ActiveConnectionsRegistry {
* Получить все активные подключения пользователя по login.
*/
public Set<ConnectionContext> getByLogin(String login) {
if (login == null) return Set.of();
if (login == null || login.isBlank()) return Set.of();
Set<ConnectionContext> set = byLogin.get(login);
if (set == null) {
return Set.of();
}
// CopyOnWriteArraySet безопасно отдавать как есть
return set;
return (set == null) ? Set.of() : set; // CopyOnWriteArraySet можно отдавать как есть
}
}

View File

@ -19,8 +19,16 @@ public final class NetExceptionResponseFactory {
String message) {
Net_Exception_Response resp = new Net_Exception_Response();
resp.setOp(req.getOp());
resp.setRequestId(req.getRequestId());
// НЕ падаем, даже если req == null
if (req != null) {
resp.setOp(req.getOp());
resp.setRequestId(req.getRequestId());
} else {
resp.setOp(null);
resp.setRequestId(null);
}
resp.setStatus(status);
resp.setCode(code);
resp.setMessage(message);

View File

@ -1,3 +1 @@
Работу с линиями
Восстановление при подвисании сервера