Добавить диагностику PWA/Push и endpoint тестового push

This commit is contained in:
AidarKC
2026-04-21 01:10:56 +03:00
parent 185ba5b1d3
commit d07602b0a9
11 changed files with 811 additions and 4 deletions
@@ -65,6 +65,7 @@ import server.logic.ws_protocol.JSON.messages.Net_CallSignalToSession_Handler;
import server.logic.ws_protocol.JSON.messages.Net_ReceiveIncomingMessage_Handler;
import server.logic.ws_protocol.JSON.messages.Net_SendDirectMessage_Handler;
import server.logic.ws_protocol.JSON.messages.Net_SendMessagePair_Handler;
import server.logic.ws_protocol.JSON.messages.Net_SendTestWebPush_Handler;
import server.logic.ws_protocol.JSON.messages.Net_UpsertPushToken_Handler;
import server.logic.ws_protocol.JSON.messages.entyties.Net_AckSessionDelivery_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_AckIncomingMessage_Request;
@@ -73,6 +74,7 @@ import server.logic.ws_protocol.JSON.messages.entyties.Net_CallSignalToSession_R
import server.logic.ws_protocol.JSON.messages.entyties.Net_ReceiveIncomingMessage_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_SendDirectMessage_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_SendMessagePair_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_SendTestWebPush_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_UpsertPushToken_Request;
// --- NEW: Ping ---
@@ -129,6 +131,7 @@ public final class JsonHandlerRegistry {
// --- direct messages / push ---
Map.entry("UpsertPushToken", new Net_UpsertPushToken_Handler()),
Map.entry("SendTestWebPush", new Net_SendTestWebPush_Handler()),
Map.entry("SendDirectMessage", new Net_SendDirectMessage_Handler()),
Map.entry("SendMessagePair", new Net_SendMessagePair_Handler()),
Map.entry("ReceiveIncomingMessage", new Net_ReceiveIncomingMessage_Handler()),
@@ -180,6 +183,7 @@ public final class JsonHandlerRegistry {
// --- direct messages / push ---
Map.entry("UpsertPushToken", Net_UpsertPushToken_Request.class),
Map.entry("SendTestWebPush", Net_SendTestWebPush_Request.class),
Map.entry("SendDirectMessage", Net_SendDirectMessage_Request.class),
Map.entry("SendMessagePair", Net_SendMessagePair_Request.class),
Map.entry("ReceiveIncomingMessage", Net_ReceiveIncomingMessage_Request.class),
@@ -0,0 +1,108 @@
package server.logic.ws_protocol.JSON.messages;
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.messages.entyties.Net_SendTestWebPush_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_SendTestWebPush_Response;
import server.logic.ws_protocol.JSON.push.WebPushSender;
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
import server.logic.ws_protocol.WireCodes;
import shine.db.dao.ActiveSessionsDAO;
import shine.db.entities.ActiveSessionEntry;
import java.util.ArrayList;
import java.util.List;
public class Net_SendTestWebPush_Handler implements JsonMessageHandler {
@Override
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) throws Exception {
Net_SendTestWebPush_Request req = (Net_SendTestWebPush_Request) baseRequest;
if (ctx == null || !ctx.isAuthenticatedUser()) {
return NetExceptionResponseFactory.error(req, WireCodes.Status.UNVERIFIED, "NOT_AUTHENTICATED", "Требуется авторизация");
}
String authLogin = String.valueOf(ctx.getLogin() == null ? "" : ctx.getLogin()).trim();
String targetLogin = String.valueOf(req.getLogin() == null ? "" : req.getLogin()).trim();
if (targetLogin.isBlank()) targetLogin = authLogin;
if (!targetLogin.equalsIgnoreCase(authLogin)) {
return NetExceptionResponseFactory.error(
req,
WireCodes.Status.UNVERIFIED,
"FORBIDDEN_TARGET_LOGIN",
"Разрешена отправка тестового push только для текущего авторизованного пользователя"
);
}
List<ActiveSessionEntry> targets = new ArrayList<>();
String targetSessionId = String.valueOf(req.getSessionId() == null ? "" : req.getSessionId()).trim();
if (!targetSessionId.isBlank()) {
ActiveSessionEntry one = ActiveSessionsDAO.getInstance().getBySessionId(targetSessionId);
if (one == null || !targetLogin.equalsIgnoreCase(one.getLogin())) {
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, "SESSION_NOT_FOUND", "Сессия для тестового push не найдена");
}
targets.add(one);
} else {
targets = ActiveSessionsDAO.getInstance().getByLogin(targetLogin);
}
String title = String.valueOf(req.getTitle() == null ? "" : req.getTitle()).trim();
if (title.isBlank()) title = "SHiNE: тестовый push";
String text = String.valueOf(req.getText() == null ? "" : req.getText()).trim();
if (text.isBlank()) text = "Тестовое push-уведомление отправлено успешно.";
int sessionsWithPushConfig = 0;
int delivered = 0;
int failed = 0;
long now = System.currentTimeMillis();
for (ActiveSessionEntry s : targets) {
if (isBlank(s.getPushEndpoint()) || isBlank(s.getPushP256dhKey()) || isBlank(s.getPushAuthKey())) {
continue;
}
sessionsWithPushConfig++;
String payload = "{\"kind\":\"test_push\",\"title\":\"" + jsonEscape(title) + "\",\"text\":\"" + jsonEscape(text) + "\",\"sentAt\":" + now + "}";
boolean ok = WebPushSender.sendBase64Payload(
s.getPushEndpoint(),
s.getPushP256dhKey(),
s.getPushAuthKey(),
payload
);
if (ok) delivered++;
else failed++;
}
Net_SendTestWebPush_Response resp = new Net_SendTestWebPush_Response();
resp.setOp(req.getOp());
resp.setRequestId(req.getRequestId());
resp.setStatus(WireCodes.Status.OK);
resp.setTargetLogin(targetLogin);
resp.setAttemptedSessions(targets.size());
resp.setSessionsWithPushConfig(sessionsWithPushConfig);
resp.setDelivered(delivered);
resp.setFailed(failed);
resp.setSentAtMs(now);
return resp;
}
private boolean isBlank(String s) {
return s == null || s.isBlank();
}
private static String jsonEscape(String s) {
if (s == null) return "";
StringBuilder out = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\\') out.append("\\\\");
else if (c == '"') out.append("\\\"");
else if (c == '\n') out.append("\\n");
else if (c == '\r') out.append("\\r");
else if (c == '\t') out.append("\\t");
else out.append(c);
}
return out.toString();
}
}
@@ -0,0 +1,22 @@
package server.logic.ws_protocol.JSON.messages.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Request;
public class Net_SendTestWebPush_Request extends Net_Request {
private String login;
private String sessionId;
private String title;
private String text;
public String getLogin() { return login; }
public void setLogin(String login) { this.login = login; }
public String getSessionId() { return sessionId; }
public void setSessionId(String sessionId) { this.sessionId = sessionId; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getText() { return text; }
public void setText(String text) { this.text = text; }
}
@@ -0,0 +1,30 @@
package server.logic.ws_protocol.JSON.messages.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Response;
public class Net_SendTestWebPush_Response extends Net_Response {
private String targetLogin;
private int attemptedSessions;
private int sessionsWithPushConfig;
private int delivered;
private int failed;
private long sentAtMs;
public String getTargetLogin() { return targetLogin; }
public void setTargetLogin(String targetLogin) { this.targetLogin = targetLogin; }
public int getAttemptedSessions() { return attemptedSessions; }
public void setAttemptedSessions(int attemptedSessions) { this.attemptedSessions = attemptedSessions; }
public int getSessionsWithPushConfig() { return sessionsWithPushConfig; }
public void setSessionsWithPushConfig(int sessionsWithPushConfig) { this.sessionsWithPushConfig = sessionsWithPushConfig; }
public int getDelivered() { return delivered; }
public void setDelivered(int delivered) { this.delivered = delivered; }
public int getFailed() { return failed; }
public void setFailed(int failed) { this.failed = failed; }
public long getSentAtMs() { return sentAtMs; }
public void setSentAtMs(long sentAtMs) { this.sentAtMs = sentAtMs; }
}