SHiNE-server/src/main/java/server/debug/DebugClientsServlet.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));
}
}