SHA256
23 01 25
Промежуточный комит. Ужас как устал сегодня, узнал что и запросы у меня постоянно закрывают сессию. Надо переделать
This commit is contained in:
-30
@@ -1,30 +0,0 @@
|
||||
//package server.logic.ws_protocol.JSON.handlers.auth;
|
||||
//
|
||||
//import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
//import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
//import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
//import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
//import server.logic.ws_protocol.JSON.handlers.auth.entyties.Net_RefreshSession_Request;
|
||||
//import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||
//import server.logic.ws_protocol.WireCodes;
|
||||
//
|
||||
///**
|
||||
// * RefreshSession (v2) — ОТКЛЮЧЕН.
|
||||
// *
|
||||
// * Раньше это был "короткий вход" (1 запрос) по sessionId+sessionPwd.
|
||||
// * Теперь вход всегда 2 шага: SessionChallenge -> SessionLogin (подпись sessionKey).
|
||||
// */
|
||||
//public class Net_RefreshSession_Handler implements JsonMessageHandler {
|
||||
//
|
||||
// @Override
|
||||
// public Net_Response handle(Net_Request request, ConnectionContext ctx) throws Exception {
|
||||
// Net_RefreshSession_Request req = (Net_RefreshSession_Request) request;
|
||||
//
|
||||
// return NetExceptionResponseFactory.error(
|
||||
// req,
|
||||
// WireCodes.Status.GONE, // 410
|
||||
// "DISABLED_V2",
|
||||
// "RefreshSession отключён в v2. Используй SessionChallenge + SessionLogin."
|
||||
// );
|
||||
// }
|
||||
//}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
//package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
//
|
||||
//import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
//
|
||||
///**
|
||||
// * Запрос RefreshSession.
|
||||
// *
|
||||
// * В новой версии (v2) RefreshSession ОТКЛЮЧЕН.
|
||||
// * Оставлен временно для совместимости, handler вернёт 410 GONE.
|
||||
// */
|
||||
//public class Net_RefreshSession_Request extends Net_Request {
|
||||
//
|
||||
// private String sessionId;
|
||||
// private String sessionPwd;
|
||||
// private String clientInfo;
|
||||
//
|
||||
// public String getSessionId() {
|
||||
// return sessionId;
|
||||
// }
|
||||
//
|
||||
// public void setSessionId(String sessionId) {
|
||||
// this.sessionId = sessionId;
|
||||
// }
|
||||
//
|
||||
// public String getSessionPwd() {
|
||||
// return sessionPwd;
|
||||
// }
|
||||
//
|
||||
// public void setSessionPwd(String sessionPwd) {
|
||||
// this.sessionPwd = sessionPwd;
|
||||
// }
|
||||
//
|
||||
// public String getClientInfo() { return clientInfo; }
|
||||
//
|
||||
// public void setClientInfo(String clientInfo) { this.clientInfo = clientInfo; }
|
||||
//}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
//package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
//
|
||||
//import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
//
|
||||
///**
|
||||
// * Ответ на RefreshSession.
|
||||
// *
|
||||
// * В новой версии (v2) RefreshSession ОТКЛЮЧЕН.
|
||||
// * Этот класс можно оставить временно для совместимости сериализации,
|
||||
// * но handler будет возвращать 410 GONE.
|
||||
// */
|
||||
//public class Net_RefreshSession_Response extends Net_Response {
|
||||
//
|
||||
// private String storagePwd;
|
||||
//
|
||||
// public String getStoragePwd() {
|
||||
// return storagePwd;
|
||||
// }
|
||||
//
|
||||
// public void setStoragePwd(String storagePwd) {
|
||||
// this.storagePwd = storagePwd;
|
||||
// }
|
||||
//}
|
||||
@@ -5,52 +5,151 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import shine.db.entities.SolanaUserEntry;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Утилита для работы с WebSocket-подключениями.
|
||||
*
|
||||
* Цель этой версии:
|
||||
* - всегда логировать "кто закрыл" / "что закрывали" / "в каком состоянии был WS";
|
||||
* - логировать исключения так, чтобы было видно первопричину;
|
||||
* - не терять контекст из-за ctx.reset() (сначала снимаем "снимок" полей).
|
||||
*/
|
||||
public final class WsConnectionUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(WsConnectionUtils.class);
|
||||
|
||||
/** Счётчик событий закрытия (удобно коррелировать логи). */
|
||||
private static final AtomicLong CLOSE_SEQ = new AtomicLong(0);
|
||||
|
||||
private WsConnectionUtils() {
|
||||
// utility
|
||||
}
|
||||
|
||||
/**
|
||||
* Корректно закрывает WebSocket-соединение:
|
||||
* - удаляет контекст из ActiveConnectionsRegistry;
|
||||
* - очищает ConnectionContext;
|
||||
* - закрывает сам WebSocket (если ещё открыт).
|
||||
*
|
||||
* @param ctx контекст соединения
|
||||
* @param statusCode код закрытия WebSocket (например, 1000, 4001)
|
||||
* @param reason причина закрытия (для логов/клиента)
|
||||
*/
|
||||
public static void closeConnection(ConnectionContext ctx, int statusCode, String reason) {
|
||||
if (ctx == null) {
|
||||
return;
|
||||
closeConnection(ctx, statusCode, reason, null, "UNKNOWN");
|
||||
}
|
||||
|
||||
/**
|
||||
* Расширенное закрытие с указанием инициатора и причины (Throwable).
|
||||
*
|
||||
* @param ctx контекст
|
||||
* @param statusCode код закрытия
|
||||
* @param reason причина (пойдёт в close frame + логи)
|
||||
* @param cause исключение/первопричина (если закрываем из catch)
|
||||
* @param initiator строка "кто инициировал" (handler/op/requestId/etc.)
|
||||
*/
|
||||
public static void closeConnection(ConnectionContext ctx,
|
||||
int statusCode,
|
||||
String reason,
|
||||
Throwable cause,
|
||||
String initiator) {
|
||||
if (ctx == null) return;
|
||||
|
||||
final long closeId = CLOSE_SEQ.incrementAndGet();
|
||||
|
||||
// --- СНИМОК КОНТЕКСТА ДО reset() ---
|
||||
final Session ws = ctx.getWsSession();
|
||||
|
||||
final String sessionId = safeString(ctx.getSessionId());
|
||||
final int authStatus = safeAuthStatus(ctx);
|
||||
|
||||
final SolanaUserEntry user = ctx.getSolanaUser();
|
||||
final String login = (user != null ? safeString(user.getLogin()) : "");
|
||||
|
||||
final String activeSessionId =
|
||||
(ctx.getActiveSession() != null ? safeString(ctx.getActiveSession().getSessionId()) : "");
|
||||
|
||||
final boolean wsPresent = (ws != null);
|
||||
final boolean wsOpen = (ws != null && safeIsOpen(ws));
|
||||
final String wsInfo = formatWsInfo(ws);
|
||||
|
||||
final String threadName = Thread.currentThread().getName();
|
||||
final int ctxId = System.identityHashCode(ctx);
|
||||
|
||||
// Логируем "начало закрытия" всегда, чтобы видеть даже случаи "ws уже закрыт"
|
||||
if (cause != null) {
|
||||
log.warn("WS_CLOSE#{} BEGIN initiator={} thread={} ctxId={} login={} sessionId={} activeSessionId={} authStatus={} statusCode={} reason={} wsPresent={} wsOpen={} wsInfo={}",
|
||||
closeId, initiator, threadName, ctxId, login, sessionId, activeSessionId, authStatus, statusCode, reason, wsPresent, wsOpen, wsInfo, cause);
|
||||
} else {
|
||||
log.info("WS_CLOSE#{} BEGIN initiator={} thread={} ctxId={} login={} sessionId={} activeSessionId={} authStatus={} statusCode={} reason={} wsPresent={} wsOpen={} wsInfo={}",
|
||||
closeId, initiator, threadName, ctxId, login, sessionId, activeSessionId, authStatus, statusCode, reason, wsPresent, wsOpen, wsInfo);
|
||||
}
|
||||
|
||||
Session ws = ctx.getWsSession();
|
||||
|
||||
// --- ШАГ 1: убрать из реестра (чтобы новые сообщения не шли в мёртвый контекст) ---
|
||||
try {
|
||||
// Удаляем контекст из реестра активных соединений
|
||||
ActiveConnectionsRegistry.getInstance().remove(ctx);
|
||||
|
||||
// Чистим контекст
|
||||
ctx.reset();
|
||||
|
||||
// Закрываем WebSocket-сессию
|
||||
if (ws != null && ws.isOpen()) {
|
||||
try {
|
||||
ws.close(statusCode, reason);
|
||||
} catch (Exception e) {
|
||||
log.warn("Не удалось закрыть WebSocket-сессию (statusCode={}, reason={})", statusCode, reason, e);
|
||||
}
|
||||
}
|
||||
log.debug("WS_CLOSE#{} registry.remove OK ctxId={} sessionId={} login={}", closeId, ctxId, sessionId, login);
|
||||
} catch (Exception e) {
|
||||
log.warn("Ошибка при закрытии WebSocket-соединения", e);
|
||||
log.warn("WS_CLOSE#{} registry.remove FAIL ctxId={} sessionId={} login={}", closeId, ctxId, sessionId, login, e);
|
||||
}
|
||||
|
||||
// --- ШАГ 2: закрыть WS (если открыт) ---
|
||||
if (ws != null) {
|
||||
if (safeIsOpen(ws)) {
|
||||
try {
|
||||
ws.close(statusCode, safeString(reason));
|
||||
log.info("WS_CLOSE#{} ws.close OK ctxId={} sessionId={} login={} statusCode={} reason={}",
|
||||
closeId, ctxId, sessionId, login, statusCode, reason);
|
||||
} catch (Exception e) {
|
||||
log.warn("WS_CLOSE#{} ws.close FAIL ctxId={} sessionId={} login={} statusCode={} reason={} wsInfo={}",
|
||||
closeId, ctxId, sessionId, login, statusCode, reason, wsInfo, e);
|
||||
}
|
||||
} else {
|
||||
log.info("WS_CLOSE#{} ws already closed ctxId={} sessionId={} login={} wsInfo={}",
|
||||
closeId, ctxId, sessionId, login, wsInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// --- ШАГ 3: очистить контекст (в конце, чтобы не потерять поля в логах выше) ---
|
||||
try {
|
||||
ctx.reset();
|
||||
log.debug("WS_CLOSE#{} ctx.reset OK ctxId={} (was sessionId={}, login={})", closeId, ctxId, sessionId, login);
|
||||
} catch (Exception e) {
|
||||
log.warn("WS_CLOSE#{} ctx.reset FAIL ctxId={} (was sessionId={}, login={})", closeId, ctxId, sessionId, login, e);
|
||||
}
|
||||
|
||||
log.info("WS_CLOSE#{} END initiator={} ctxId={} sessionId={} login={}", closeId, initiator, ctxId, sessionId, login);
|
||||
}
|
||||
|
||||
private static String safeString(String s) {
|
||||
return (s == null ? "" : s);
|
||||
}
|
||||
|
||||
private static int safeAuthStatus(ConnectionContext ctx) {
|
||||
try {
|
||||
return ctx.getAuthenticationStatus();
|
||||
} catch (Exception e) {
|
||||
return -999;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean safeIsOpen(Session ws) {
|
||||
try {
|
||||
return ws.isOpen();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatWsInfo(Session ws) {
|
||||
if (ws == null) return "null";
|
||||
|
||||
String remote = "";
|
||||
String local = "";
|
||||
try {
|
||||
SocketAddress ra = ws.getRemoteAddress();
|
||||
remote = (ra != null ? ra.toString() : "");
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
try {
|
||||
SocketAddress la = ws.getLocalAddress();
|
||||
local = (la != null ? la.toString() : "");
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
return "remote=" + remote + ", local=" + local;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user