SHA256
Добавлен временный debug API для автотеста WebRTC и runbook
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package server.debug;
|
||||
|
||||
import jakarta.servlet.Servlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
||||
/**
|
||||
* Регистрирует HTTP debug endpoints.
|
||||
*/
|
||||
public final class DebugApiConfigurator {
|
||||
|
||||
private DebugApiConfigurator() {
|
||||
}
|
||||
|
||||
public static void register(ServletContextHandler context) {
|
||||
DebugTokenProvider tokenProvider = DebugTokenProvider.loadFromProjectRoot();
|
||||
|
||||
addServlet(context, new DebugClientsServlet(tokenProvider), "/debug/ws/clients");
|
||||
addServlet(context, new DebugConnectServlet(tokenProvider), "/debug/ws/connect");
|
||||
addServlet(context, new DebugLogsServlet(tokenProvider), "/debug/ws/logs");
|
||||
}
|
||||
|
||||
private static void addServlet(ServletContextHandler context, Servlet servlet, String path) {
|
||||
ServletHolder holder = new ServletHolder(servlet);
|
||||
context.addServlet(holder, path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package server.debug;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import shine.db.dao.ActiveSessionsDAO;
|
||||
import shine.db.entities.ActiveSessionEntry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* GET /debug/ws/clients
|
||||
*/
|
||||
public class DebugClientsServlet extends HttpServlet {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private final DebugTokenProvider tokenProvider;
|
||||
|
||||
public DebugClientsServlet(DebugTokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
if (!tokenProvider.isEnabled()) {
|
||||
writeError(resp, 503, "DEBUG_DISABLED", "Debug API отключен: .debug-token не найден или пуст");
|
||||
return;
|
||||
}
|
||||
if (!tokenProvider.matchesBearerHeader(req.getHeader("Authorization"))) {
|
||||
writeError(resp, 401, "UNAUTHORIZED", "Неверный Bearer token");
|
||||
return;
|
||||
}
|
||||
|
||||
List<ConnectionContext> contexts = ActiveConnectionsRegistry.getInstance().getAllConnectionsSnapshot();
|
||||
List<ObjectNode> rows = new ArrayList<>();
|
||||
for (ConnectionContext ctx : contexts) {
|
||||
Session ws = ctx.getWsSession();
|
||||
if (ws == null || !ws.isOpen()) continue;
|
||||
|
||||
ObjectNode row = MAPPER.createObjectNode();
|
||||
String sessionId = safe(ctx.getSessionId());
|
||||
row.put("sessionId", sessionId);
|
||||
row.put("login", safe(ctx.getLogin()));
|
||||
row.put("authStatus", ctx.getAuthenticationStatus());
|
||||
row.put("wsOpen", ws.isOpen());
|
||||
|
||||
String remote = safeRemote(ws.getRemoteAddress());
|
||||
row.put("remoteAddress", remote);
|
||||
row.put("ip", extractIp(ws.getRemoteAddress()));
|
||||
row.put("userAgent", safeUserAgent(ws));
|
||||
|
||||
ActiveSessionEntry active = null;
|
||||
try {
|
||||
if (!sessionId.isBlank()) {
|
||||
active = ActiveSessionsDAO.getInstance().getBySessionId(sessionId);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
row.put("clientInfoFromClient", active != null ? safe(active.getClientInfoFromClient()) : "");
|
||||
row.put("clientInfoFromRequest", active != null ? safe(active.getClientInfoFromRequest()) : "");
|
||||
row.put("userLanguage", active != null ? safe(active.getUserLanguage()) : "");
|
||||
row.put("sessionCreatedAtMs", active != null ? active.getSessionCreatedAtMs() : 0L);
|
||||
|
||||
rows.add(row);
|
||||
}
|
||||
|
||||
rows.sort(Comparator.comparing(a -> a.path("sessionId").asText("")));
|
||||
|
||||
ArrayNode clients = MAPPER.createArrayNode();
|
||||
rows.forEach(clients::add);
|
||||
|
||||
ObjectNode payload = MAPPER.createObjectNode();
|
||||
payload.put("count", clients.size());
|
||||
payload.set("clients", clients);
|
||||
|
||||
writeOk(resp, payload);
|
||||
}
|
||||
|
||||
private static String safeUserAgent(Session ws) {
|
||||
try {
|
||||
if (ws.getUpgradeRequest() == null) return "";
|
||||
return safe(ws.getUpgradeRequest().getHeader("User-Agent"));
|
||||
} catch (Throwable ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static String extractIp(SocketAddress addr) {
|
||||
if (addr instanceof InetSocketAddress inet) {
|
||||
if (inet.getAddress() != null) {
|
||||
return safe(inet.getAddress().getHostAddress());
|
||||
}
|
||||
return safe(inet.getHostString());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String safeRemote(SocketAddress addr) {
|
||||
return addr == null ? "" : safe(addr.toString());
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private static void writeOk(HttpServletResponse resp, ObjectNode payload) throws IOException {
|
||||
ObjectNode root = MAPPER.createObjectNode();
|
||||
root.put("ok", true);
|
||||
root.set("payload", payload == null ? MAPPER.createObjectNode() : payload);
|
||||
writeJson(resp, 200, root);
|
||||
}
|
||||
|
||||
private static void writeError(HttpServletResponse resp, int status, String code, String message) throws IOException {
|
||||
ObjectNode root = MAPPER.createObjectNode();
|
||||
root.put("ok", false);
|
||||
root.put("code", code);
|
||||
root.put("message", message);
|
||||
writeJson(resp, status, root);
|
||||
}
|
||||
|
||||
private static void writeJson(HttpServletResponse resp, int status, ObjectNode root) throws IOException {
|
||||
resp.setStatus(status);
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.setContentType("application/json; charset=UTF-8");
|
||||
resp.getWriter().write(MAPPER.writeValueAsString(root));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package server.debug;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.push.WsEventSender;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* POST /debug/ws/connect
|
||||
*/
|
||||
public class DebugConnectServlet extends HttpServlet {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private final DebugTokenProvider tokenProvider;
|
||||
|
||||
public DebugConnectServlet(DebugTokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
if (!tokenProvider.isEnabled()) {
|
||||
writeError(resp, 503, "DEBUG_DISABLED", "Debug API отключен: .debug-token не найден или пуст");
|
||||
return;
|
||||
}
|
||||
if (!tokenProvider.matchesBearerHeader(req.getHeader("Authorization"))) {
|
||||
writeError(resp, 401, "UNAUTHORIZED", "Неверный Bearer token");
|
||||
return;
|
||||
}
|
||||
|
||||
JsonNode body;
|
||||
try {
|
||||
body = MAPPER.readTree(req.getInputStream());
|
||||
} catch (Exception e) {
|
||||
writeError(resp, 400, "BAD_JSON", "Тело запроса должно быть JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
String initiatorSessionId = text(body, "initiatorSessionId");
|
||||
String responderSessionId = text(body, "responderSessionId");
|
||||
boolean clearDebugLog = body != null && body.path("clearDebugLog").asBoolean(false);
|
||||
|
||||
if (initiatorSessionId.isBlank() || responderSessionId.isBlank()) {
|
||||
writeError(resp, 400, "BAD_FIELDS", "initiatorSessionId и responderSessionId обязательны");
|
||||
return;
|
||||
}
|
||||
if (initiatorSessionId.equals(responderSessionId)) {
|
||||
writeError(resp, 400, "BAD_FIELDS", "Нужны две разные sessionId");
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionContext initiator = ActiveConnectionsRegistry.getInstance().getBySessionId(initiatorSessionId);
|
||||
ConnectionContext responder = ActiveConnectionsRegistry.getInstance().getBySessionId(responderSessionId);
|
||||
|
||||
if (initiator == null || initiator.getWsSession() == null || !initiator.getWsSession().isOpen()) {
|
||||
writeError(resp, 404, "INITIATOR_NOT_FOUND", "Сессия initiator не найдена или неактивна");
|
||||
return;
|
||||
}
|
||||
if (responder == null || responder.getWsSession() == null || !responder.getWsSession().isOpen()) {
|
||||
writeError(resp, 404, "RESPONDER_NOT_FOUND", "Сессия responder не найдена или неактивна");
|
||||
return;
|
||||
}
|
||||
|
||||
DebugRunLogBuffer logs = DebugRunLogBuffer.getInstance();
|
||||
if (clearDebugLog) {
|
||||
logs.clear();
|
||||
}
|
||||
String runId = logs.newRunId();
|
||||
String callId = "debug-call-" + System.currentTimeMillis();
|
||||
|
||||
ObjectNode responderPayload = MAPPER.createObjectNode();
|
||||
responderPayload.put("runId", runId);
|
||||
responderPayload.put("callId", callId);
|
||||
responderPayload.put("peerSessionId", initiatorSessionId);
|
||||
responderPayload.put("peerLogin", safe(initiator.getLogin()));
|
||||
responderPayload.put("role", "responder");
|
||||
responderPayload.put("issuedAtMs", System.currentTimeMillis());
|
||||
|
||||
ObjectNode initiatorPayload = MAPPER.createObjectNode();
|
||||
initiatorPayload.put("runId", runId);
|
||||
initiatorPayload.put("callId", callId);
|
||||
initiatorPayload.put("peerSessionId", responderSessionId);
|
||||
initiatorPayload.put("peerLogin", safe(responder.getLogin()));
|
||||
initiatorPayload.put("role", "initiator");
|
||||
initiatorPayload.put("issuedAtMs", System.currentTimeMillis());
|
||||
|
||||
boolean responderOk = WsEventSender.sendEvent(responder, "DebugConnectPrepareResponder", "evt-" + callId + "-r", responderPayload);
|
||||
boolean initiatorOk = WsEventSender.sendEvent(initiator, "DebugConnectStartInitiator", "evt-" + callId + "-i", initiatorPayload);
|
||||
|
||||
logs.add("info", runId, "debug-connect", initiatorSessionId, safe(initiator.getLogin()),
|
||||
"Запуск debug-run", "initiator->" + responderSessionId + ", sentResponder=" + responderOk + ", sentInitiator=" + initiatorOk);
|
||||
|
||||
ObjectNode payload = MAPPER.createObjectNode();
|
||||
payload.put("runId", runId);
|
||||
payload.put("callId", callId);
|
||||
payload.put("accepted", responderOk && initiatorOk);
|
||||
payload.put("initiatorSessionId", initiatorSessionId);
|
||||
payload.put("responderSessionId", responderSessionId);
|
||||
payload.put("initiatorLogin", safe(initiator.getLogin()));
|
||||
payload.put("responderLogin", safe(responder.getLogin()));
|
||||
if (!safe(initiator.getLogin()).equalsIgnoreCase(safe(responder.getLogin()))) {
|
||||
payload.put("mode", "cross-login");
|
||||
} else {
|
||||
payload.put("warning", "Сессии принадлежат одному login, рекомендован тест между разными login");
|
||||
}
|
||||
|
||||
writeOk(resp, payload);
|
||||
}
|
||||
|
||||
private static String text(JsonNode node, String field) {
|
||||
if (node == null) return "";
|
||||
return safe(node.path(field).asText(""));
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private static void writeOk(HttpServletResponse resp, ObjectNode payload) throws IOException {
|
||||
ObjectNode root = MAPPER.createObjectNode();
|
||||
root.put("ok", true);
|
||||
root.set("payload", payload == null ? MAPPER.createObjectNode() : payload);
|
||||
writeJson(resp, 200, root);
|
||||
}
|
||||
|
||||
private static void writeError(HttpServletResponse resp, int status, String code, String message) throws IOException {
|
||||
ObjectNode root = MAPPER.createObjectNode();
|
||||
root.put("ok", false);
|
||||
root.put("code", code);
|
||||
root.put("message", message);
|
||||
writeJson(resp, status, root);
|
||||
}
|
||||
|
||||
private static void writeJson(HttpServletResponse resp, int status, ObjectNode root) throws IOException {
|
||||
resp.setStatus(status);
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.setContentType("application/json; charset=UTF-8");
|
||||
resp.getWriter().write(MAPPER.writeValueAsString(root));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package server.debug;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* GET /debug/ws/logs?limit=200&runId=dbg-...
|
||||
*/
|
||||
public class DebugLogsServlet extends HttpServlet {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private final DebugTokenProvider tokenProvider;
|
||||
|
||||
public DebugLogsServlet(DebugTokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
if (!tokenProvider.isEnabled()) {
|
||||
writeError(resp, 503, "DEBUG_DISABLED", "Debug API отключен: .debug-token не найден или пуст");
|
||||
return;
|
||||
}
|
||||
if (!tokenProvider.matchesBearerHeader(req.getHeader("Authorization"))) {
|
||||
writeError(resp, 401, "UNAUTHORIZED", "Неверный Bearer token");
|
||||
return;
|
||||
}
|
||||
|
||||
int limit = parseLimit(req.getParameter("limit"));
|
||||
String runId = safe(req.getParameter("runId"));
|
||||
|
||||
List<DebugRunLogBuffer.Entry> list = DebugRunLogBuffer.getInstance().tail(limit, runId);
|
||||
|
||||
ArrayNode rows = MAPPER.createArrayNode();
|
||||
for (DebugRunLogBuffer.Entry e : list) {
|
||||
ObjectNode row = MAPPER.createObjectNode();
|
||||
row.put("ts", e.ts);
|
||||
row.put("level", e.level);
|
||||
row.put("runId", e.runId);
|
||||
row.put("source", e.source);
|
||||
row.put("sessionId", e.sessionId);
|
||||
row.put("login", e.login);
|
||||
row.put("message", e.message);
|
||||
row.put("details", e.details);
|
||||
rows.add(row);
|
||||
}
|
||||
|
||||
ObjectNode payload = MAPPER.createObjectNode();
|
||||
payload.put("count", rows.size());
|
||||
payload.put("limit", limit);
|
||||
payload.put("runIdFilter", runId);
|
||||
payload.set("logs", rows);
|
||||
|
||||
writeOk(resp, payload);
|
||||
}
|
||||
|
||||
private static int parseLimit(String raw) {
|
||||
try {
|
||||
int n = Integer.parseInt(String.valueOf(raw));
|
||||
if (n < 1) return 100;
|
||||
return Math.min(n, 1000);
|
||||
} catch (Exception e) {
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private static void writeOk(HttpServletResponse resp, ObjectNode payload) throws IOException {
|
||||
ObjectNode root = MAPPER.createObjectNode();
|
||||
root.put("ok", true);
|
||||
root.set("payload", payload == null ? MAPPER.createObjectNode() : payload);
|
||||
writeJson(resp, 200, root);
|
||||
}
|
||||
|
||||
private static void writeError(HttpServletResponse resp, int status, String code, String message) throws IOException {
|
||||
ObjectNode root = MAPPER.createObjectNode();
|
||||
root.put("ok", false);
|
||||
root.put("code", code);
|
||||
root.put("message", message);
|
||||
writeJson(resp, status, root);
|
||||
}
|
||||
|
||||
private static void writeJson(HttpServletResponse resp, int status, ObjectNode root) throws IOException {
|
||||
resp.setStatus(status);
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
resp.setContentType("application/json; charset=UTF-8");
|
||||
resp.getWriter().write(MAPPER.writeValueAsString(root));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package server.debug;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Потокобезопасный in-memory буфер debug-логов.
|
||||
*/
|
||||
public final class DebugRunLogBuffer {
|
||||
|
||||
public static final class Entry {
|
||||
public long ts;
|
||||
public String level;
|
||||
public String runId;
|
||||
public String source;
|
||||
public String sessionId;
|
||||
public String login;
|
||||
public String message;
|
||||
public String details;
|
||||
}
|
||||
|
||||
private static final DebugRunLogBuffer INSTANCE = new DebugRunLogBuffer(5_000);
|
||||
|
||||
public static DebugRunLogBuffer getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private final int capacity;
|
||||
private final Deque<Entry> entries = new ArrayDeque<>();
|
||||
|
||||
private DebugRunLogBuffer(int capacity) {
|
||||
this.capacity = Math.max(100, capacity);
|
||||
}
|
||||
|
||||
public synchronized String newRunId() {
|
||||
return "dbg-" + UUID.randomUUID();
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
public synchronized void add(String level, String runId, String source, String sessionId, String login, String message, String details) {
|
||||
Entry e = new Entry();
|
||||
e.ts = System.currentTimeMillis();
|
||||
e.level = safe(level, "info");
|
||||
e.runId = safe(runId, "");
|
||||
e.source = safe(source, "server");
|
||||
e.sessionId = safe(sessionId, "");
|
||||
e.login = safe(login, "");
|
||||
e.message = safe(message, "");
|
||||
e.details = safe(details, "");
|
||||
|
||||
entries.addLast(e);
|
||||
while (entries.size() > capacity) {
|
||||
entries.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized List<Entry> tail(int limit, String runIdFilter) {
|
||||
int capped = Math.max(1, Math.min(limit, 1000));
|
||||
String filter = safe(runIdFilter, "");
|
||||
|
||||
List<Entry> out = new ArrayList<>(capped);
|
||||
Object[] arr = entries.toArray();
|
||||
for (int i = arr.length - 1; i >= 0 && out.size() < capped; i--) {
|
||||
Entry e = (Entry) arr[i];
|
||||
if (!filter.isBlank() && !filter.equals(e.runId)) continue;
|
||||
out.add(e);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static String safe(String value, String fallback) {
|
||||
String s = value == null ? "" : value.trim();
|
||||
return s.isBlank() ? fallback : s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package server.debug;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Загружает debug token из файла .debug-token в корне проекта.
|
||||
*/
|
||||
public final class DebugTokenProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(DebugTokenProvider.class);
|
||||
private static final String TOKEN_FILE_NAME = ".debug-token";
|
||||
|
||||
private final String token;
|
||||
|
||||
private DebugTokenProvider(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public static DebugTokenProvider loadFromProjectRoot() {
|
||||
Path tokenPath = Path.of(TOKEN_FILE_NAME).toAbsolutePath().normalize();
|
||||
String loaded = "";
|
||||
try {
|
||||
if (Files.exists(tokenPath)) {
|
||||
loaded = Files.readString(tokenPath, StandardCharsets.UTF_8).trim();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Не удалось прочитать debug token из {}", tokenPath, e);
|
||||
}
|
||||
|
||||
if (loaded.isBlank()) {
|
||||
log.warn("⚠️ Debug API отключены: файл {} отсутствует или пуст.", tokenPath);
|
||||
} else {
|
||||
log.info("✅ Debug API включены, token файл найден: {}", tokenPath);
|
||||
}
|
||||
return new DebugTokenProvider(loaded);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return token != null && !token.isBlank();
|
||||
}
|
||||
|
||||
public boolean matchesBearerHeader(String authorizationHeader) {
|
||||
if (!isEnabled()) return false;
|
||||
if (authorizationHeader == null || authorizationHeader.isBlank()) return false;
|
||||
if (!authorizationHeader.startsWith("Bearer ")) return false;
|
||||
String actual = authorizationHeader.substring("Bearer ".length()).trim();
|
||||
return token.equals(actual);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.debug.DebugApiConfigurator;
|
||||
import utils.config.AppConfig;
|
||||
|
||||
import java.time.Duration;
|
||||
@@ -58,6 +59,9 @@ public final class WsServer {
|
||||
context.setContextPath("/");
|
||||
server.setHandler(context);
|
||||
|
||||
// HTTP debug API
|
||||
DebugApiConfigurator.register(context);
|
||||
|
||||
// Инициализация контейнера WebSocket
|
||||
JettyWebSocketServletContainerInitializer.configure(context, (servletContext, wsContainer) -> {
|
||||
// Таймаут простоя соединения (Jetty 11 синтаксис)
|
||||
|
||||
Reference in New Issue
Block a user