141 lines
5.2 KiB
Java
141 lines
5.2 KiB
Java
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));
|
|
}
|
|
}
|