Удалён AckIncomingMessage и обновлена документация доставки

This commit is contained in:
AidarKC 2026-05-02 17:02:57 +03:00
parent c44d755ce0
commit b05da86197
6 changed files with 19 additions and 54 deletions

View File

@ -1,2 +1,2 @@
client.version=1.2.35
server.version=1.2.29
client.version=1.2.36
server.version=1.2.30

View File

@ -60,7 +60,6 @@ import server.logic.ws_protocol.JSON.handlers.connections.Net_ListContacts_Handl
import server.logic.ws_protocol.JSON.handlers.connections.entyties.Net_GetUserConnectionsGraph_Request;
import server.logic.ws_protocol.JSON.handlers.connections.entyties.Net_AddCloseFriend_Request;
import server.logic.ws_protocol.JSON.handlers.connections.entyties.Net_ListContacts_Request;
import server.logic.ws_protocol.JSON.messages.Net_AckIncomingMessage_Handler;
import server.logic.ws_protocol.JSON.messages.Net_AckSessionDelivery_Handler;
import server.logic.ws_protocol.JSON.messages.Net_CallInviteBroadcast_Handler;
import server.logic.ws_protocol.JSON.messages.Net_CallSignalToSession_Handler;
@ -70,7 +69,6 @@ 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;
import server.logic.ws_protocol.JSON.messages.entyties.Net_CallInviteBroadcast_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_CallSignalToSession_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_ReceiveIncomingMessage_Request;
@ -145,7 +143,6 @@ public final class JsonHandlerRegistry {
Map.entry("SendMessagePair", new Net_SendMessagePair_Handler()),
Map.entry("ReceiveOutcomingMessage", new Net_SendMessagePair_Handler()),
Map.entry("ReceiveIncomingMessage", new Net_ReceiveIncomingMessage_Handler()),
Map.entry("AckIncomingMessage", new Net_AckIncomingMessage_Handler()),
Map.entry("AckSessionDelivery", new Net_AckSessionDelivery_Handler()),
Map.entry("CallInviteBroadcast", new Net_CallInviteBroadcast_Handler()),
Map.entry("CallSignalToSession", new Net_CallSignalToSession_Handler()),
@ -202,7 +199,6 @@ public final class JsonHandlerRegistry {
Map.entry("SendMessagePair", Net_SendMessagePair_Request.class),
Map.entry("ReceiveOutcomingMessage", Net_SendMessagePair_Request.class),
Map.entry("ReceiveIncomingMessage", Net_ReceiveIncomingMessage_Request.class),
Map.entry("AckIncomingMessage", Net_AckIncomingMessage_Request.class),
Map.entry("AckSessionDelivery", Net_AckSessionDelivery_Request.class),
Map.entry("CallInviteBroadcast", Net_CallInviteBroadcast_Request.class),
Map.entry("CallSignalToSession", Net_CallSignalToSession_Request.class),

View File

@ -1,29 +0,0 @@
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_AckIncomingMessage_Request;
import server.logic.ws_protocol.JSON.messages.entyties.Net_AckIncomingMessage_Response;
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
import server.logic.ws_protocol.WireCodes;
public class Net_AckIncomingMessage_Handler implements JsonMessageHandler {
@Override
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
Net_AckIncomingMessage_Request req = (Net_AckIncomingMessage_Request) baseRequest;
if (ctx == null || !ctx.isAuthenticatedUser()) {
return NetExceptionResponseFactory.error(req, WireCodes.Status.UNVERIFIED, "NOT_AUTHENTICATED", "Требуется авторизация");
}
if (req.getEventId() != null && !req.getEventId().isBlank()) {
DeliveryTracker.getInstance().ack(req.getEventId());
}
Net_AckIncomingMessage_Response resp = new Net_AckIncomingMessage_Response();
resp.setOp(req.getOp());
resp.setRequestId(req.getRequestId());
resp.setStatus(WireCodes.Status.OK);
return resp;
}
}

View File

@ -1,13 +0,0 @@
package server.logic.ws_protocol.JSON.messages.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Request;
public class Net_AckIncomingMessage_Request extends Net_Request {
private String eventId;
private String messageId;
public String getEventId() { return eventId; }
public void setEventId(String eventId) { this.eventId = eventId; }
public String getMessageId() { return messageId; }
public void setMessageId(String messageId) { this.messageId = messageId; }
}

View File

@ -1,6 +0,0 @@
package server.logic.ws_protocol.JSON.messages.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Response;
public class Net_AckIncomingMessage_Response extends Net_Response {
}

View File

@ -16,6 +16,23 @@
5. Если пара реально добавилась в БД, сервер запускает realtime-доставку в активные сессии целевых пользователей.
6. Если это дубль, дальнейшая доставка не выполняется (повтор не разгоняется).
## Как сообщение доходит до клиента (WS + WebPush)
1. После успешной записи сервер пытается доставить сообщение во все активные сессии `targetLogin`.
2. Для каждой сессии сервер сначала создаёт/проверяет запись доставки в `signed_message_session_delivery` (pending).
3. Если сессия онлайн, сервер шлёт `SignedMessageArrived` по WebSocket.
4. Если сессия офлайн и тип сообщения входящий текст (`TYPE_INCOMING_TEXT`), сервер пробует WebPush (если у сессии сохранены `endpoint/p256dh/auth`).
5. При следующем логине/переподключении сервер дочитывает pending-сообщения и повторно отправляет их в эту сессию как backlog.
## Подтверждение доставки (ACK)
- Используется метод `AckSessionDelivery`.
- Клиент отправляет ACK после обработки `SignedMessageArrived` с `messageKey`.
- Сервер помечает `(messageKey, sessionId)` как `delivered=1`, и это сообщение перестаёт быть pending для этой сессии.
### Важно про безопасность ACK
- `AckSessionDelivery` требует авторизованную WS-сессию (`ctx.isAuthenticatedUser()`).
- `sessionId` берётся сервером из текущего `ConnectionContext`, а не из payload запроса.
- Поэтому подтвердить доставку «просто зная messageKey/sessionId» без авторизованной сессии нельзя.
## Почему допускаются дубли сети
- В модели с несколькими серверами возможны повторные пересылки одного и того же сообщения.
- Дедупликация делается на уровне БД по ключам записи.