SHA256
Сервер: дочистить legacy-слои и доки
This commit is contained in:
+1
-1
@@ -29,7 +29,7 @@ import java.sql.SQLException;
|
|||||||
* отдельным recovery/resync-слоем после успешного commit.
|
* отдельным recovery/resync-слоем после успешного commit.
|
||||||
*
|
*
|
||||||
* Важный смысл текущей реализации:
|
* Важный смысл текущей реализации:
|
||||||
* - мы НЕ трогаем identity-слой (`solana_users`) и НЕ трогаем DM-таблицы;
|
* - мы НЕ трогаем current users слой (`solana_user_pda_current`) и НЕ трогаем DM-таблицы;
|
||||||
* - мы очищаем только блокчейн пользователя и derived-state, который строится из неё;
|
* - мы очищаем только блокчейн пользователя и derived-state, который строится из неё;
|
||||||
* - висячие cross-chain ссылки в чужих blocks допускаются как нормальное поведение системы.
|
* - висячие cross-chain ссылки в чужих blocks допускаются как нормальное поведение системы.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public final class BlockchainStateDAO {
|
|||||||
* Строгая вставка state только если записи ещё нет.
|
* Строгая вставка state только если записи ещё нет.
|
||||||
*
|
*
|
||||||
* Нужна для recovery / resync:
|
* Нужна для recovery / resync:
|
||||||
* - identity пользователя уже может существовать в solana_users;
|
* - runtime-проекция пользователя уже может существовать в current users слое;
|
||||||
* - в таком случае нам надо восстановить только blockchain_state;
|
* - в таком случае нам надо восстановить только blockchain_state;
|
||||||
* - если запись уже есть, метод просто ничего не меняет.
|
* - если запись уже есть, метод просто ничего не меняет.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+27
-27
@@ -1,7 +1,7 @@
|
|||||||
package shine.db.dao;
|
package shine.db.dao;
|
||||||
|
|
||||||
import shine.db.DbController;
|
import shine.db.DbController;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
@@ -11,7 +11,7 @@ import java.sql.Statement;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class SignedMessagesV2DAO {
|
public final class SignedMessagesDAO {
|
||||||
|
|
||||||
public enum ApplyStatus {
|
public enum ApplyStatus {
|
||||||
APPLIED,
|
APPLIED,
|
||||||
@@ -24,21 +24,21 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static volatile SignedMessagesV2DAO instance;
|
private static volatile SignedMessagesDAO instance;
|
||||||
private final DbController db = DbController.getInstance();
|
private final DbController db = DbController.getInstance();
|
||||||
|
|
||||||
private SignedMessagesV2DAO() {}
|
private SignedMessagesDAO() {}
|
||||||
|
|
||||||
public static SignedMessagesV2DAO getInstance() {
|
public static SignedMessagesDAO getInstance() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
synchronized (SignedMessagesV2DAO.class) {
|
synchronized (SignedMessagesDAO.class) {
|
||||||
if (instance == null) instance = new SignedMessagesV2DAO();
|
if (instance == null) instance = new SignedMessagesDAO();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplyStatus insertIfAbsent(SignedMessageV2Entry e) throws Exception {
|
public ApplyStatus insertIfAbsent(SignedMessageEntry e) throws Exception {
|
||||||
return withBusyRetry(() -> {
|
return withBusyRetry(() -> {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
if (isBlockedByConversationDelete(c, e.getFromLogin(), e.getToLogin(), e.getTimeMs())) {
|
if (isBlockedByConversationDelete(c, e.getFromLogin(), e.getToLogin(), e.getTimeMs())) {
|
||||||
@@ -65,7 +65,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean insertPairBothOrNothing(SignedMessageV2Entry first, SignedMessageV2Entry second) throws Exception {
|
public boolean insertPairBothOrNothing(SignedMessageEntry first, SignedMessageEntry second) throws Exception {
|
||||||
return withBusyRetry(() -> {
|
return withBusyRetry(() -> {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
boolean prevAutoCommit = c.getAutoCommit();
|
boolean prevAutoCommit = c.getAutoCommit();
|
||||||
@@ -94,7 +94,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplyStatus upsertContentPair(SignedMessageV2Entry incoming, SignedMessageV2Entry outgoing) throws Exception {
|
public ApplyStatus upsertContentPair(SignedMessageEntry incoming, SignedMessageEntry outgoing) throws Exception {
|
||||||
return withBusyRetry(() -> {
|
return withBusyRetry(() -> {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
boolean prevAutoCommit = c.getAutoCommit();
|
boolean prevAutoCommit = c.getAutoCommit();
|
||||||
@@ -135,7 +135,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplyStatus upsertIncomingCopy(SignedMessageV2Entry incoming) throws Exception {
|
public ApplyStatus upsertIncomingCopy(SignedMessageEntry incoming) throws Exception {
|
||||||
return withBusyRetry(() -> {
|
return withBusyRetry(() -> {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
boolean prevAutoCommit = c.getAutoCommit();
|
boolean prevAutoCommit = c.getAutoCommit();
|
||||||
@@ -172,7 +172,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplyStatus applyDeleteMessage(SignedMessageV2Entry tombstone) throws Exception {
|
public ApplyStatus applyDeleteMessage(SignedMessageEntry tombstone) throws Exception {
|
||||||
return withBusyRetry(() -> {
|
return withBusyRetry(() -> {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
boolean prevAutoCommit = c.getAutoCommit();
|
boolean prevAutoCommit = c.getAutoCommit();
|
||||||
@@ -203,7 +203,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplyStatus applyDeleteConversation(SignedMessageV2Entry tombstone) throws Exception {
|
public ApplyStatus applyDeleteConversation(SignedMessageEntry tombstone) throws Exception {
|
||||||
return withBusyRetry(() -> {
|
return withBusyRetry(() -> {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
boolean prevAutoCommit = c.getAutoCommit();
|
boolean prevAutoCommit = c.getAutoCommit();
|
||||||
@@ -231,7 +231,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignedMessageV2Entry getByMessageKey(String messageKey) throws Exception {
|
public SignedMessageEntry getByMessageKey(String messageKey) throws Exception {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT
|
SELECT
|
||||||
@@ -252,7 +252,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignedMessageV2Entry getLatestConversationDelete(String fromLogin, String toLogin) throws Exception {
|
public SignedMessageEntry getLatestConversationDelete(String fromLogin, String toLogin) throws Exception {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
return getLatestConversationDelete(c, fromLogin, toLogin);
|
return getLatestConversationDelete(c, fromLogin, toLogin);
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SignedMessageV2Entry> listPendingForSession(String login, String sessionId) throws Exception {
|
public List<SignedMessageEntry> listPendingForSession(String login, String sessionId) throws Exception {
|
||||||
return withBusyRetry(() -> {
|
return withBusyRetry(() -> {
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
String fillSql = """
|
String fillSql = """
|
||||||
@@ -354,7 +354,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
WHERE d.session_id = ? AND d.delivered = 0
|
WHERE d.session_id = ? AND d.delivered = 0
|
||||||
ORDER BY m.time_ms ASC, m.revision_time_ms ASC, m.reencrypted_at_ms ASC, m.created_at_ms ASC
|
ORDER BY m.time_ms ASC, m.revision_time_ms ASC, m.reencrypted_at_ms ASC, m.created_at_ms ASC
|
||||||
""".formatted(messagesTable());
|
""".formatted(messagesTable());
|
||||||
List<SignedMessageV2Entry> out = new ArrayList<>();
|
List<SignedMessageEntry> out = new ArrayList<>();
|
||||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||||
ps.setString(1, sessionId);
|
ps.setString(1, sessionId);
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
@@ -366,7 +366,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SignedMessageV2Entry> listConversationPage(
|
public List<SignedMessageEntry> listConversationPage(
|
||||||
String login,
|
String login,
|
||||||
String peerLogin,
|
String peerLogin,
|
||||||
long beforeTimeMs,
|
long beforeTimeMs,
|
||||||
@@ -395,7 +395,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
ORDER BY time_ms DESC, message_key DESC
|
ORDER BY time_ms DESC, message_key DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
""".formatted(messagesTable());
|
""".formatted(messagesTable());
|
||||||
List<SignedMessageV2Entry> out = new ArrayList<>();
|
List<SignedMessageEntry> out = new ArrayList<>();
|
||||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||||
ps.setString(1, login);
|
ps.setString(1, login);
|
||||||
ps.setString(2, login);
|
ps.setString(2, login);
|
||||||
@@ -416,7 +416,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void upsertMessage(Connection c, SignedMessageV2Entry e) throws SQLException {
|
private void upsertMessage(Connection c, SignedMessageEntry e) throws SQLException {
|
||||||
String sql = """
|
String sql = """
|
||||||
INSERT INTO %s (
|
INSERT INTO %s (
|
||||||
message_key, base_key, target_login, from_login, to_login,
|
message_key, base_key, target_login, from_login, to_login,
|
||||||
@@ -448,7 +448,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markMessageReadByReceipt(Connection c, SignedMessageV2Entry entry) throws SQLException {
|
private void markMessageReadByReceipt(Connection c, SignedMessageEntry entry) throws SQLException {
|
||||||
if (entry == null) return;
|
if (entry == null) return;
|
||||||
int messageType = entry.getMessageType();
|
int messageType = entry.getMessageType();
|
||||||
if (messageType != 3 && messageType != 4) return;
|
if (messageType != 3 && messageType != 4) return;
|
||||||
@@ -552,7 +552,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SignedMessageV2Entry getLatestConversationDelete(Connection c, String fromLogin, String toLogin) throws Exception {
|
private SignedMessageEntry getLatestConversationDelete(Connection c, String fromLogin, String toLogin) throws Exception {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT
|
SELECT
|
||||||
message_key, base_key, target_login, from_login, to_login,
|
message_key, base_key, target_login, from_login, to_login,
|
||||||
@@ -646,7 +646,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int insertStrict(Connection c, SignedMessageV2Entry e) throws SQLException {
|
private int insertStrict(Connection c, SignedMessageEntry e) throws SQLException {
|
||||||
String sql = """
|
String sql = """
|
||||||
INSERT INTO %s (
|
INSERT INTO %s (
|
||||||
message_key, base_key, target_login, from_login, to_login,
|
message_key, base_key, target_login, from_login, to_login,
|
||||||
@@ -661,7 +661,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindSignedMessage(PreparedStatement ps, SignedMessageV2Entry e) throws SQLException {
|
private void bindSignedMessage(PreparedStatement ps, SignedMessageEntry e) throws SQLException {
|
||||||
ps.setString(1, e.getMessageKey());
|
ps.setString(1, e.getMessageKey());
|
||||||
ps.setString(2, e.getBaseKey());
|
ps.setString(2, e.getBaseKey());
|
||||||
ps.setString(3, e.getTargetLogin());
|
ps.setString(3, e.getTargetLogin());
|
||||||
@@ -718,8 +718,8 @@ public final class SignedMessagesV2DAO {
|
|||||||
return "signed_messages";
|
return "signed_messages";
|
||||||
}
|
}
|
||||||
|
|
||||||
private SignedMessageV2Entry mapRow(ResultSet rs) throws Exception {
|
private SignedMessageEntry mapRow(ResultSet rs) throws Exception {
|
||||||
SignedMessageV2Entry e = new SignedMessageV2Entry();
|
SignedMessageEntry e = new SignedMessageEntry();
|
||||||
e.setMessageKey(rs.getString("message_key"));
|
e.setMessageKey(rs.getString("message_key"));
|
||||||
e.setBaseKey(rs.getString("base_key"));
|
e.setBaseKey(rs.getString("base_key"));
|
||||||
e.setTargetLogin(rs.getString("target_login"));
|
e.setTargetLogin(rs.getString("target_login"));
|
||||||
@@ -743,7 +743,7 @@ public final class SignedMessagesV2DAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private record RevisionMarker(long revisionTimeMs, long reencryptedAtMs) {
|
private record RevisionMarker(long revisionTimeMs, long reencryptedAtMs) {
|
||||||
private static RevisionMarker of(SignedMessageV2Entry entry) {
|
private static RevisionMarker of(SignedMessageEntry entry) {
|
||||||
return new RevisionMarker(entry.getRevisionTimeMs(), entry.getReencryptedAtMs());
|
return new RevisionMarker(entry.getRevisionTimeMs(), entry.getReencryptedAtMs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package shine.db.entities;
|
package shine.db.entities;
|
||||||
|
|
||||||
public class SignedMessageV2Entry {
|
public class SignedMessageEntry {
|
||||||
private String messageKey;
|
private String messageKey;
|
||||||
private String baseKey;
|
private String baseKey;
|
||||||
private String targetLogin;
|
private String targetLogin;
|
||||||
+8
-8
@@ -25,8 +25,8 @@ public class ConnectionContext {
|
|||||||
public static final int AUTH_STATUS_AUTH_IN_PROGRESS = 1; // выполнен challenge (AuthChallenge или SessionChallenge)
|
public static final int AUTH_STATUS_AUTH_IN_PROGRESS = 1; // выполнен challenge (AuthChallenge или SessionChallenge)
|
||||||
public static final int AUTH_STATUS_USER = 2; // авторизованный пользователь
|
public static final int AUTH_STATUS_USER = 2; // авторизованный пользователь
|
||||||
|
|
||||||
// Полный пользователь из БД (solana_users)
|
// Полный пользователь из runtime БД (current users / solana_user_pda_current)
|
||||||
private CurrentUserEntry solanaUserEntry;
|
private CurrentUserEntry currentUserEntry;
|
||||||
|
|
||||||
// Активная сессия из БД (active_sessions)
|
// Активная сессия из БД (active_sessions)
|
||||||
private ActiveSessionEntry activeSessionEntry;
|
private ActiveSessionEntry activeSessionEntry;
|
||||||
@@ -89,12 +89,12 @@ public class ConnectionContext {
|
|||||||
|
|
||||||
// --- SolanaUser / ActiveSession ---
|
// --- SolanaUser / ActiveSession ---
|
||||||
|
|
||||||
public CurrentUserEntry getSolanaUser() {
|
public CurrentUserEntry getCurrentUser() {
|
||||||
return solanaUserEntry;
|
return currentUserEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSolanaUser(CurrentUserEntry solanaUserEntry) {
|
public void setCurrentUser(CurrentUserEntry currentUserEntry) {
|
||||||
this.solanaUserEntry = solanaUserEntry;
|
this.currentUserEntry = currentUserEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActiveSessionEntry getActiveSession() {
|
public ActiveSessionEntry getActiveSession() {
|
||||||
@@ -108,7 +108,7 @@ public class ConnectionContext {
|
|||||||
// --- Удобный геттер для логина ---
|
// --- Удобный геттер для логина ---
|
||||||
|
|
||||||
public String getLogin() {
|
public String getLogin() {
|
||||||
return solanaUserEntry != null ? solanaUserEntry.getLogin() : null;
|
return currentUserEntry != null ? currentUserEntry.getLogin() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- sessionId ---
|
// --- sessionId ---
|
||||||
@@ -176,7 +176,7 @@ public class ConnectionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
solanaUserEntry = null;
|
currentUserEntry = null;
|
||||||
activeSessionEntry = null;
|
activeSessionEntry = null;
|
||||||
|
|
||||||
sessionId = null;
|
sessionId = null;
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ public class Net_AuthChallenge_Handler implements JsonMessageHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.setSolanaUser(solanaUserEntry);
|
ctx.setCurrentUser(solanaUserEntry);
|
||||||
ctx.setAuthenticationStatus(ConnectionContext.AUTH_STATUS_AUTH_IN_PROGRESS);
|
ctx.setAuthenticationStatus(ConnectionContext.AUTH_STATUS_AUTH_IN_PROGRESS);
|
||||||
|
|
||||||
byte[] buf = new byte[32];
|
byte[] buf = new byte[32];
|
||||||
|
|||||||
+2
-2
@@ -42,7 +42,7 @@ public class Net_CloseActiveSession_Handler implements JsonMessageHandler {
|
|||||||
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
||||||
Net_CloseActiveSession_Request req = (Net_CloseActiveSession_Request) baseReq;
|
Net_CloseActiveSession_Request req = (Net_CloseActiveSession_Request) baseReq;
|
||||||
|
|
||||||
if (ctx == null || ctx.getSolanaUser() == null || ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_USER) {
|
if (ctx == null || ctx.getCurrentUser() == null || ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_USER) {
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.UNVERIFIED,
|
WireCodes.Status.UNVERIFIED,
|
||||||
@@ -51,7 +51,7 @@ public class Net_CloseActiveSession_Handler implements JsonMessageHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentUserEntry user = ctx.getSolanaUser();
|
CurrentUserEntry user = ctx.getCurrentUser();
|
||||||
String currentLogin = user.getLogin();
|
String currentLogin = user.getLogin();
|
||||||
|
|
||||||
String targetSessionId = req.getSessionId();
|
String targetSessionId = req.getSessionId();
|
||||||
|
|||||||
+2
-2
@@ -58,7 +58,7 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
Net_CreateAuthSession_Request req = (Net_CreateAuthSession_Request) baseReq;
|
Net_CreateAuthSession_Request req = (Net_CreateAuthSession_Request) baseReq;
|
||||||
|
|
||||||
if (ctx == null
|
if (ctx == null
|
||||||
|| ctx.getSolanaUser() == null
|
|| ctx.getCurrentUser() == null
|
||||||
|| ctx.getAuthNonce() == null
|
|| ctx.getAuthNonce() == null
|
||||||
|| ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_AUTH_IN_PROGRESS) {
|
|| ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_AUTH_IN_PROGRESS) {
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentUserEntry userFromContext = ctx.getSolanaUser();
|
CurrentUserEntry userFromContext = ctx.getCurrentUser();
|
||||||
String loginFromContext = userFromContext.getLogin();
|
String loginFromContext = userFromContext.getLogin();
|
||||||
String loginFromReq = req.getLogin();
|
String loginFromReq = req.getLogin();
|
||||||
if (loginFromReq == null || loginFromReq.isBlank()) {
|
if (loginFromReq == null || loginFromReq.isBlank()) {
|
||||||
|
|||||||
+2
-2
@@ -36,7 +36,7 @@ public class Net_ListSessions_Handler implements JsonMessageHandler {
|
|||||||
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
||||||
Net_ListSessions_Request req = (Net_ListSessions_Request) baseReq;
|
Net_ListSessions_Request req = (Net_ListSessions_Request) baseReq;
|
||||||
|
|
||||||
if (ctx == null || ctx.getSolanaUser() == null || ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_USER) {
|
if (ctx == null || ctx.getCurrentUser() == null || ctx.getAuthenticationStatus() != ConnectionContext.AUTH_STATUS_USER) {
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.UNVERIFIED,
|
WireCodes.Status.UNVERIFIED,
|
||||||
@@ -45,7 +45,7 @@ public class Net_ListSessions_Handler implements JsonMessageHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentUserEntry user = ctx.getSolanaUser();
|
CurrentUserEntry user = ctx.getCurrentUser();
|
||||||
String currentLogin = user.getLogin();
|
String currentLogin = user.getLogin();
|
||||||
|
|
||||||
List<ActiveSessionEntry> sessions;
|
List<ActiveSessionEntry> sessions;
|
||||||
|
|||||||
+1
-1
@@ -294,7 +294,7 @@ public class Net_SessionLogin_Handler implements JsonMessageHandler {
|
|||||||
|
|
||||||
// ctx
|
// ctx
|
||||||
ctx.setActiveSession(session);
|
ctx.setActiveSession(session);
|
||||||
ctx.setSolanaUser(user);
|
ctx.setCurrentUser(user);
|
||||||
ctx.setSessionId(sessionId);
|
ctx.setSessionId(sessionId);
|
||||||
ctx.setAuthenticationStatus(ConnectionContext.AUTH_STATUS_USER);
|
ctx.setAuthenticationStatus(ConnectionContext.AUTH_STATUS_USER);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ public class Net_GetFriendsLists_Handler implements JsonMessageHandler {
|
|||||||
|
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
|
|
||||||
// 1) Канонизируем login через solana_users (NOCASE)
|
// 1) Канонизируем login через current users слой (NOCASE)
|
||||||
String canonicalLogin = findCanonicalLogin(c, loginAnyCase);
|
String canonicalLogin = findCanonicalLogin(c, loginAnyCase);
|
||||||
if (canonicalLogin == null) {
|
if (canonicalLogin == null) {
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
|
|||||||
+2
-2
@@ -17,8 +17,8 @@ import shine.db.entities.CurrentUserEntry;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* GetSyncUserProfile — server-to-server профиль пользователя для межсерверной синхронизации.
|
* GetSyncUserProfile — server-to-server профиль пользователя для межсерверной синхронизации.
|
||||||
* Нужен, чтобы принимающий сервер мог создать локальные solana_users + blockchain_state
|
* Нужен, чтобы принимающий сервер мог создать локальную runtime-проекцию пользователя
|
||||||
* без прямого запроса в Solana RPC.
|
* и blockchain_state без прямого запроса в Solana RPC.
|
||||||
*/
|
*/
|
||||||
public final class Net_GetSyncUserProfile_Handler implements JsonMessageHandler {
|
public final class Net_GetSyncUserProfile_Handler implements JsonMessageHandler {
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -8,7 +8,7 @@ import server.logic.ws_protocol.JSON.messages.entyties.Net_AckSessionDelivery_Re
|
|||||||
import server.logic.ws_protocol.JSON.messages.entyties.Net_AckSessionDelivery_Response;
|
import server.logic.ws_protocol.JSON.messages.entyties.Net_AckSessionDelivery_Response;
|
||||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||||
import server.logic.ws_protocol.WireCodes;
|
import server.logic.ws_protocol.WireCodes;
|
||||||
import shine.db.dao.SignedMessagesV2DAO;
|
import shine.db.dao.SignedMessagesDAO;
|
||||||
|
|
||||||
public class Net_AckSessionDelivery_Handler implements JsonMessageHandler {
|
public class Net_AckSessionDelivery_Handler implements JsonMessageHandler {
|
||||||
@Override
|
@Override
|
||||||
@@ -22,7 +22,7 @@ public class Net_AckSessionDelivery_Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String messageKey = req.getMessageKey().trim();
|
String messageKey = req.getMessageKey().trim();
|
||||||
SignedMessagesV2DAO.getInstance().markDelivered(messageKey, ctx.getSessionId(), System.currentTimeMillis());
|
SignedMessagesDAO.getInstance().markDelivered(messageKey, ctx.getSessionId(), System.currentTimeMillis());
|
||||||
|
|
||||||
Net_AckSessionDelivery_Response resp = new Net_AckSessionDelivery_Response();
|
Net_AckSessionDelivery_Response resp = new Net_AckSessionDelivery_Response();
|
||||||
resp.setOp(req.getOp());
|
resp.setOp(req.getOp());
|
||||||
|
|||||||
+4
-4
@@ -9,8 +9,8 @@ import server.logic.ws_protocol.JSON.messages.entyties.Net_DeleteConversation_Re
|
|||||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||||
import server.logic.ws_protocol.WireCodes;
|
import server.logic.ws_protocol.WireCodes;
|
||||||
import server.sync.DmFederationService;
|
import server.sync.DmFederationService;
|
||||||
import shine.db.dao.SignedMessagesV2DAO;
|
import shine.db.dao.SignedMessagesDAO;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
|
|
||||||
public class Net_DeleteConversation_Handler implements JsonMessageHandler {
|
public class Net_DeleteConversation_Handler implements JsonMessageHandler {
|
||||||
@Override
|
@Override
|
||||||
@@ -38,8 +38,8 @@ public class Net_DeleteConversation_Handler implements JsonMessageHandler {
|
|||||||
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedMessageV2Entry entry = SignedMessagesCore.toEntry(block, "DeleteConversation", null);
|
SignedMessageEntry entry = SignedMessagesCore.toEntry(block, "DeleteConversation", null);
|
||||||
SignedMessagesV2DAO.ApplyStatus status = SignedMessagesV2DAO.getInstance().applyDeleteConversation(entry);
|
SignedMessagesDAO.ApplyStatus status = SignedMessagesDAO.getInstance().applyDeleteConversation(entry);
|
||||||
|
|
||||||
SignedMessagesRealtime.DeliveryCounters counters = new SignedMessagesRealtime.DeliveryCounters();
|
SignedMessagesRealtime.DeliveryCounters counters = new SignedMessagesRealtime.DeliveryCounters();
|
||||||
if (status.applied()) {
|
if (status.applied()) {
|
||||||
|
|||||||
+4
-4
@@ -9,8 +9,8 @@ import server.logic.ws_protocol.JSON.messages.entyties.Net_DeleteMessage_Respons
|
|||||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||||
import server.logic.ws_protocol.WireCodes;
|
import server.logic.ws_protocol.WireCodes;
|
||||||
import server.sync.DmFederationService;
|
import server.sync.DmFederationService;
|
||||||
import shine.db.dao.SignedMessagesV2DAO;
|
import shine.db.dao.SignedMessagesDAO;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
|
|
||||||
public class Net_DeleteMessage_Handler implements JsonMessageHandler {
|
public class Net_DeleteMessage_Handler implements JsonMessageHandler {
|
||||||
@Override
|
@Override
|
||||||
@@ -38,8 +38,8 @@ public class Net_DeleteMessage_Handler implements JsonMessageHandler {
|
|||||||
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedMessageV2Entry entry = SignedMessagesCore.toEntry(block, "DeleteMessage", null);
|
SignedMessageEntry entry = SignedMessagesCore.toEntry(block, "DeleteMessage", null);
|
||||||
SignedMessagesV2DAO.ApplyStatus status = SignedMessagesV2DAO.getInstance().applyDeleteMessage(entry);
|
SignedMessagesDAO.ApplyStatus status = SignedMessagesDAO.getInstance().applyDeleteMessage(entry);
|
||||||
|
|
||||||
SignedMessagesRealtime.DeliveryCounters counters = new SignedMessagesRealtime.DeliveryCounters();
|
SignedMessagesRealtime.DeliveryCounters counters = new SignedMessagesRealtime.DeliveryCounters();
|
||||||
if (status.applied()) {
|
if (status.applied()) {
|
||||||
|
|||||||
+4
-4
@@ -10,8 +10,8 @@ import server.logic.ws_protocol.JSON.messages.entyties.Net_GetDirectMessages_Req
|
|||||||
import server.logic.ws_protocol.JSON.messages.entyties.Net_GetDirectMessages_Response;
|
import server.logic.ws_protocol.JSON.messages.entyties.Net_GetDirectMessages_Response;
|
||||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||||
import server.logic.ws_protocol.WireCodes;
|
import server.logic.ws_protocol.WireCodes;
|
||||||
import shine.db.dao.SignedMessagesV2DAO;
|
import shine.db.dao.SignedMessagesDAO;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
@@ -43,7 +43,7 @@ public class Net_GetDirectMessages_Handler implements JsonMessageHandler {
|
|||||||
String beforeMessageKey = req.getBeforeMessageKey() == null ? "" : req.getBeforeMessageKey().trim();
|
String beforeMessageKey = req.getBeforeMessageKey() == null ? "" : req.getBeforeMessageKey().trim();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<SignedMessageV2Entry> page = SignedMessagesV2DAO.getInstance().listConversationPage(
|
List<SignedMessageEntry> page = SignedMessagesDAO.getInstance().listConversationPage(
|
||||||
login,
|
login,
|
||||||
peerLogin,
|
peerLogin,
|
||||||
beforeTimeMs,
|
beforeTimeMs,
|
||||||
@@ -66,7 +66,7 @@ public class Net_GetDirectMessages_Handler implements JsonMessageHandler {
|
|||||||
resp.setHasMore(hasMore);
|
resp.setHasMore(hasMore);
|
||||||
|
|
||||||
List<Net_GetDirectMessages_Response.MessageItem> items = new ArrayList<>();
|
List<Net_GetDirectMessages_Response.MessageItem> items = new ArrayList<>();
|
||||||
for (SignedMessageV2Entry entry : page) {
|
for (SignedMessageEntry entry : page) {
|
||||||
Net_GetDirectMessages_Response.MessageItem item = new Net_GetDirectMessages_Response.MessageItem();
|
Net_GetDirectMessages_Response.MessageItem item = new Net_GetDirectMessages_Response.MessageItem();
|
||||||
item.setMessageKey(entry.getMessageKey());
|
item.setMessageKey(entry.getMessageKey());
|
||||||
item.setBaseKey(entry.getBaseKey());
|
item.setBaseKey(entry.getBaseKey());
|
||||||
|
|||||||
+8
-8
@@ -8,8 +8,8 @@ import server.logic.ws_protocol.JSON.messages.entyties.Net_ReceiveIncomingMessag
|
|||||||
import server.logic.ws_protocol.JSON.messages.entyties.Net_ReceiveIncomingMessage_Response;
|
import server.logic.ws_protocol.JSON.messages.entyties.Net_ReceiveIncomingMessage_Response;
|
||||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||||
import server.logic.ws_protocol.WireCodes;
|
import server.logic.ws_protocol.WireCodes;
|
||||||
import shine.db.dao.SignedMessagesV2DAO;
|
import shine.db.dao.SignedMessagesDAO;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
@@ -40,21 +40,21 @@ public class Net_ReceiveIncomingMessage_Handler implements JsonMessageHandler {
|
|||||||
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
||||||
}
|
}
|
||||||
|
|
||||||
final SignedMessageV2Entry entry;
|
final SignedMessageEntry entry;
|
||||||
try {
|
try {
|
||||||
entry = SignedMessagesCore.toEntry(incoming, "ReceiveIncomingMessage", null);
|
entry = SignedMessagesCore.toEntry(incoming, "ReceiveIncomingMessage", null);
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, ex.getMessage(), "Некорректный payload подтверждения");
|
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, ex.getMessage(), "Некорректный payload подтверждения");
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedMessagesV2DAO.ApplyStatus status = incoming.isContentType()
|
SignedMessagesDAO.ApplyStatus status = incoming.isContentType()
|
||||||
? SignedMessagesV2DAO.getInstance().upsertIncomingCopy(entry)
|
? SignedMessagesDAO.getInstance().upsertIncomingCopy(entry)
|
||||||
: SignedMessagesV2DAO.getInstance().insertIfAbsent(entry);
|
: SignedMessagesDAO.getInstance().insertIfAbsent(entry);
|
||||||
SignedMessagesRealtime.DeliveryCounters counters = new SignedMessagesRealtime.DeliveryCounters();
|
SignedMessagesRealtime.DeliveryCounters counters = new SignedMessagesRealtime.DeliveryCounters();
|
||||||
if (status.applied()) {
|
if (status.applied()) {
|
||||||
counters = SignedMessagesRealtime.deliverToRelevantSessions(entry, incoming);
|
counters = SignedMessagesRealtime.deliverToRelevantSessions(entry, incoming);
|
||||||
}
|
}
|
||||||
if (status == SignedMessagesV2DAO.ApplyStatus.BLOCKED_BY_CONVERSATION_TOMBSTONE) {
|
if (status == SignedMessagesDAO.ApplyStatus.BLOCKED_BY_CONVERSATION_TOMBSTONE) {
|
||||||
bounceConversationDeleteIfKnown(incoming.fromLogin, incoming.toLogin);
|
bounceConversationDeleteIfKnown(incoming.fromLogin, incoming.toLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ public class Net_ReceiveIncomingMessage_Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bounceConversationDeleteIfKnown(String fromLogin, String toLogin) throws Exception {
|
private void bounceConversationDeleteIfKnown(String fromLogin, String toLogin) throws Exception {
|
||||||
SignedMessageV2Entry tombstone = SignedMessagesV2DAO.getInstance().getLatestConversationDelete(fromLogin, toLogin);
|
SignedMessageEntry tombstone = SignedMessagesDAO.getInstance().getLatestConversationDelete(fromLogin, toLogin);
|
||||||
if (tombstone == null || tombstone.getRawBlock() == null || tombstone.getRawBlock().length == 0) return;
|
if (tombstone == null || tombstone.getRawBlock() == null || tombstone.getRawBlock().length == 0) return;
|
||||||
server.sync.DmFederationService.fanOutDeleteConversation(
|
server.sync.DmFederationService.fanOutDeleteConversation(
|
||||||
tombstone.getFromLogin(),
|
tombstone.getFromLogin(),
|
||||||
|
|||||||
+11
-11
@@ -9,8 +9,8 @@ import server.logic.ws_protocol.JSON.messages.entyties.Net_SendMessagePair_Respo
|
|||||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||||
import server.logic.ws_protocol.WireCodes;
|
import server.logic.ws_protocol.WireCodes;
|
||||||
import server.sync.DmFederationService;
|
import server.sync.DmFederationService;
|
||||||
import shine.db.dao.SignedMessagesV2DAO;
|
import shine.db.dao.SignedMessagesDAO;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
@@ -41,8 +41,8 @@ public class Net_SendMessagePair_Handler implements JsonMessageHandler {
|
|||||||
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
return NetExceptionResponseFactory.error(req, status, code, "Сообщение не прошло проверку");
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedMessageV2Entry incomingEntry;
|
SignedMessageEntry incomingEntry;
|
||||||
SignedMessageV2Entry outgoingEntry;
|
SignedMessageEntry outgoingEntry;
|
||||||
try {
|
try {
|
||||||
String sourceApi = "SendMessagePair";
|
String sourceApi = "SendMessagePair";
|
||||||
String originSessionId = (ctx != null && !isBlank(ctx.getSessionId())) ? ctx.getSessionId() : null;
|
String originSessionId = (ctx != null && !isBlank(ctx.getSessionId())) ? ctx.getSessionId() : null;
|
||||||
@@ -52,15 +52,15 @@ public class Net_SendMessagePair_Handler implements JsonMessageHandler {
|
|||||||
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, ex.getMessage(), "Некорректный payload подтверждения");
|
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, ex.getMessage(), "Некорректный payload подтверждения");
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedMessagesV2DAO.ApplyStatus pairStatus;
|
SignedMessagesDAO.ApplyStatus pairStatus;
|
||||||
if (incoming.isContentType()) {
|
if (incoming.isContentType()) {
|
||||||
pairStatus = SignedMessagesV2DAO.getInstance().upsertContentPair(
|
pairStatus = SignedMessagesDAO.getInstance().upsertContentPair(
|
||||||
incomingEntry, outgoingEntry
|
incomingEntry, outgoingEntry
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
pairStatus = SignedMessagesV2DAO.getInstance().insertPairBothOrNothing(incomingEntry, outgoingEntry)
|
pairStatus = SignedMessagesDAO.getInstance().insertPairBothOrNothing(incomingEntry, outgoingEntry)
|
||||||
? SignedMessagesV2DAO.ApplyStatus.APPLIED
|
? SignedMessagesDAO.ApplyStatus.APPLIED
|
||||||
: SignedMessagesV2DAO.ApplyStatus.DUPLICATE_OR_OLDER;
|
: SignedMessagesDAO.ApplyStatus.DUPLICATE_OR_OLDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedMessagesRealtime.DeliveryCounters inCounters = new SignedMessagesRealtime.DeliveryCounters();
|
SignedMessagesRealtime.DeliveryCounters inCounters = new SignedMessagesRealtime.DeliveryCounters();
|
||||||
@@ -77,7 +77,7 @@ public class Net_SendMessagePair_Handler implements JsonMessageHandler {
|
|||||||
outCounters = SignedMessagesRealtime.deliverToRelevantSessions(outgoingEntry, outgoing, excludeSessionId);
|
outCounters = SignedMessagesRealtime.deliverToRelevantSessions(outgoingEntry, outgoing, excludeSessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pairStatus == SignedMessagesV2DAO.ApplyStatus.BLOCKED_BY_CONVERSATION_TOMBSTONE) {
|
if (pairStatus == SignedMessagesDAO.ApplyStatus.BLOCKED_BY_CONVERSATION_TOMBSTONE) {
|
||||||
bounceConversationDeleteIfKnown(incoming.fromLogin, incoming.toLogin);
|
bounceConversationDeleteIfKnown(incoming.fromLogin, incoming.toLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ public class Net_SendMessagePair_Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bounceConversationDeleteIfKnown(String fromLogin, String toLogin) throws Exception {
|
private void bounceConversationDeleteIfKnown(String fromLogin, String toLogin) throws Exception {
|
||||||
SignedMessageV2Entry tombstone = SignedMessagesV2DAO.getInstance().getLatestConversationDelete(fromLogin, toLogin);
|
SignedMessageEntry tombstone = SignedMessagesDAO.getInstance().getLatestConversationDelete(fromLogin, toLogin);
|
||||||
if (tombstone == null || tombstone.getRawBlock() == null || tombstone.getRawBlock().length == 0) return;
|
if (tombstone == null || tombstone.getRawBlock() == null || tombstone.getRawBlock().length == 0) return;
|
||||||
DmFederationService.fanOutDeleteConversation(
|
DmFederationService.fanOutDeleteConversation(
|
||||||
tombstone.getFromLogin(),
|
tombstone.getFromLogin(),
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ public class Net_SendSignal_Handler implements JsonMessageHandler {
|
|||||||
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, "TIME_SKEW", "Время клиента отличается от сервера более чем на 30 секунд");
|
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, "TIME_SKEW", "Время клиента отличается от сервера более чем на 30 секунд");
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentUserEntry senderUser = ctx.getSolanaUser();
|
CurrentUserEntry senderUser = ctx.getCurrentUser();
|
||||||
if (senderUser == null || senderUser.getClientKey() == null || senderUser.getClientKey().isBlank()) {
|
if (senderUser == null || senderUser.getClientKey() == null || senderUser.getClientKey().isBlank()) {
|
||||||
return NetExceptionResponseFactory.error(req, WireCodes.Status.SERVER_DATA_ERROR, "NO_CLIENT_KEY", "Для пользователя не найден client key");
|
return NetExceptionResponseFactory.error(req, WireCodes.Status.SERVER_DATA_ERROR, "NO_CLIENT_KEY", "Для пользователя не найден client key");
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
package server.logic.ws_protocol.JSON.messages;
|
package server.logic.ws_protocol.JSON.messages;
|
||||||
|
|
||||||
import shine.db.dao.CurrentUsersDAO;
|
import shine.db.dao.CurrentUsersDAO;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
import shine.db.entities.CurrentUserEntry;
|
import shine.db.entities.CurrentUserEntry;
|
||||||
import utils.crypto.Ed25519Util;
|
import utils.crypto.Ed25519Util;
|
||||||
|
|
||||||
@@ -96,11 +96,11 @@ final class SignedMessagesCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SignedMessageV2Entry toEntry(SignedMessageBlock block, String sourceApi, String originSessionId) {
|
static SignedMessageEntry toEntry(SignedMessageBlock block, String sourceApi, String originSessionId) {
|
||||||
String baseKey = SignedMessageKeys.baseKey(block.toLogin, block.fromLogin, block.timeMs, block.nonce);
|
String baseKey = SignedMessageKeys.baseKey(block.toLogin, block.fromLogin, block.timeMs, block.nonce);
|
||||||
String messageKey = SignedMessageKeys.messageKey(block.toLogin, block.fromLogin, block.timeMs, block.nonce, block.messageType);
|
String messageKey = SignedMessageKeys.messageKey(block.toLogin, block.fromLogin, block.timeMs, block.nonce, block.messageType);
|
||||||
|
|
||||||
SignedMessageV2Entry entry = new SignedMessageV2Entry();
|
SignedMessageEntry entry = new SignedMessageEntry();
|
||||||
entry.setMessageKey(messageKey);
|
entry.setMessageKey(messageKey);
|
||||||
entry.setBaseKey(baseKey);
|
entry.setBaseKey(baseKey);
|
||||||
entry.setTargetLogin(primaryTargetLogin(block));
|
entry.setTargetLogin(primaryTargetLogin(block));
|
||||||
|
|||||||
+11
-11
@@ -9,9 +9,9 @@ import server.logic.ws_protocol.JSON.ConnectionContext;
|
|||||||
import server.logic.ws_protocol.JSON.push.WebPushSender;
|
import server.logic.ws_protocol.JSON.push.WebPushSender;
|
||||||
import server.logic.ws_protocol.JSON.push.WsEventSender;
|
import server.logic.ws_protocol.JSON.push.WsEventSender;
|
||||||
import shine.db.dao.ActiveSessionsDAO;
|
import shine.db.dao.ActiveSessionsDAO;
|
||||||
import shine.db.dao.SignedMessagesV2DAO;
|
import shine.db.dao.SignedMessagesDAO;
|
||||||
import shine.db.entities.ActiveSessionEntry;
|
import shine.db.entities.ActiveSessionEntry;
|
||||||
import shine.db.entities.SignedMessageV2Entry;
|
import shine.db.entities.SignedMessageEntry;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
@@ -37,12 +37,12 @@ public final class SignedMessagesRealtime {
|
|||||||
|
|
||||||
private SignedMessagesRealtime() {}
|
private SignedMessagesRealtime() {}
|
||||||
|
|
||||||
static DeliveryCounters deliverToRelevantSessions(SignedMessageV2Entry message, SignedMessageBlock block) throws Exception {
|
static DeliveryCounters deliverToRelevantSessions(SignedMessageEntry message, SignedMessageBlock block) throws Exception {
|
||||||
return deliverToRelevantSessions(message, block, null);
|
return deliverToRelevantSessions(message, block, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DeliveryCounters deliverToRelevantSessions(
|
static DeliveryCounters deliverToRelevantSessions(
|
||||||
SignedMessageV2Entry message,
|
SignedMessageEntry message,
|
||||||
SignedMessageBlock block,
|
SignedMessageBlock block,
|
||||||
String excludeSessionId
|
String excludeSessionId
|
||||||
) throws Exception {
|
) throws Exception {
|
||||||
@@ -58,7 +58,7 @@ public final class SignedMessagesRealtime {
|
|||||||
}
|
}
|
||||||
sessionIdsToTrack.add(sessionId);
|
sessionIdsToTrack.add(sessionId);
|
||||||
}
|
}
|
||||||
SignedMessagesV2DAO.getInstance().ensureDeliveryRows(message.getMessageKey(), sessionIdsToTrack, now);
|
SignedMessagesDAO.getInstance().ensureDeliveryRows(message.getMessageKey(), sessionIdsToTrack, now);
|
||||||
for (ActiveSessionEntry s : sessions) {
|
for (ActiveSessionEntry s : sessions) {
|
||||||
String sessionId = s.getSessionId();
|
String sessionId = s.getSessionId();
|
||||||
if (excludeSessionId != null && excludeSessionId.equals(sessionId)) {
|
if (excludeSessionId != null && excludeSessionId.equals(sessionId)) {
|
||||||
@@ -97,9 +97,9 @@ public final class SignedMessagesRealtime {
|
|||||||
|
|
||||||
private static void dispatchPendingForSession(String login, String sessionId) {
|
private static void dispatchPendingForSession(String login, String sessionId) {
|
||||||
try {
|
try {
|
||||||
List<SignedMessageV2Entry> pending = SignedMessagesV2DAO.getInstance()
|
List<SignedMessageEntry> pending = SignedMessagesDAO.getInstance()
|
||||||
.listPendingForSession(login, sessionId);
|
.listPendingForSession(login, sessionId);
|
||||||
for (SignedMessageV2Entry e : pending) {
|
for (SignedMessageEntry e : pending) {
|
||||||
sendEventToSessionIfOnline(sessionId, login, e, true);
|
sendEventToSessionIfOnline(sessionId, login, e, true);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -110,7 +110,7 @@ public final class SignedMessagesRealtime {
|
|||||||
private static boolean sendEventToSessionIfOnline(
|
private static boolean sendEventToSessionIfOnline(
|
||||||
String sessionId,
|
String sessionId,
|
||||||
String actualTargetLogin,
|
String actualTargetLogin,
|
||||||
SignedMessageV2Entry message,
|
SignedMessageEntry message,
|
||||||
boolean backlog
|
boolean backlog
|
||||||
) {
|
) {
|
||||||
ConnectionContext targetCtx = ActiveConnectionsRegistry.getInstance().getBySessionId(sessionId);
|
ConnectionContext targetCtx = ActiveConnectionsRegistry.getInstance().getBySessionId(sessionId);
|
||||||
@@ -134,14 +134,14 @@ public final class SignedMessagesRealtime {
|
|||||||
return WsEventSender.sendEvent(targetCtx, "SignedMessageArrived", message.getMessageKey(), payload);
|
return WsEventSender.sendEvent(targetCtx, "SignedMessageArrived", message.getMessageKey(), payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldPushNewIncomingMessage(String targetLogin, SignedMessageV2Entry message, SignedMessageBlock block) {
|
private static boolean shouldPushNewIncomingMessage(String targetLogin, SignedMessageEntry message, SignedMessageBlock block) {
|
||||||
if (block == null) return false;
|
if (block == null) return false;
|
||||||
if (message.getMessageType() != SignedMessageBlock.TYPE_INCOMING_TEXT) return false;
|
if (message.getMessageType() != SignedMessageBlock.TYPE_INCOMING_TEXT) return false;
|
||||||
if (!targetLogin.equalsIgnoreCase(message.getToLogin())) return false;
|
if (!targetLogin.equalsIgnoreCase(message.getToLogin())) return false;
|
||||||
return block.revisionTimeMs == 0;
|
return block.revisionTimeMs == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean pushNewMessageNotification(ActiveSessionEntry session, SignedMessageV2Entry message) {
|
private static boolean pushNewMessageNotification(ActiveSessionEntry session, SignedMessageEntry message) {
|
||||||
try {
|
try {
|
||||||
if (session == null) return false;
|
if (session == null) return false;
|
||||||
if (isBlank(session.getPushEndpoint()) || isBlank(session.getPushP256dhKey()) || isBlank(session.getPushAuthKey())) {
|
if (isBlank(session.getPushEndpoint()) || isBlank(session.getPushP256dhKey()) || isBlank(session.getPushAuthKey())) {
|
||||||
@@ -160,7 +160,7 @@ public final class SignedMessagesRealtime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> targetLoginsForMessage(SignedMessageV2Entry message) {
|
private static List<String> targetLoginsForMessage(SignedMessageEntry message) {
|
||||||
Set<String> out = new LinkedHashSet<>();
|
Set<String> out = new LinkedHashSet<>();
|
||||||
int type = message.getMessageType();
|
int type = message.getMessageType();
|
||||||
if (type == SignedMessageBlock.TYPE_INCOMING_TEXT || type == SignedMessageBlock.TYPE_READ_INCOMING) {
|
if (type == SignedMessageBlock.TYPE_INCOMING_TEXT || type == SignedMessageBlock.TYPE_READ_INCOMING) {
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ public final class WsConnectionUtils {
|
|||||||
final String sessionId = safeString(ctx.getSessionId());
|
final String sessionId = safeString(ctx.getSessionId());
|
||||||
final int authStatus = safeAuthStatus(ctx);
|
final int authStatus = safeAuthStatus(ctx);
|
||||||
|
|
||||||
final CurrentUserEntry user = ctx.getSolanaUser();
|
final CurrentUserEntry user = ctx.getCurrentUser();
|
||||||
final String login = (user != null ? safeString(user.getLogin()) : "");
|
final String login = (user != null ? safeString(user.getLogin()) : "");
|
||||||
|
|
||||||
final String activeSessionId =
|
final String activeSessionId =
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ solana.users.sync.pollIntervalSeconds=300
|
|||||||
# false - брать профиль пользователя напрямую из Solana PDA (обычный режим).
|
# false - брать профиль пользователя напрямую из Solana PDA (обычный режим).
|
||||||
# true - не ходить в Solana RPC, а запрашивать у сервера-партнёра специальный
|
# true - не ходить в Solana RPC, а запрашивать у сервера-партнёра специальный
|
||||||
# sync-профиль пользователя и по нему локально создавать
|
# sync-профиль пользователя и по нему локально создавать
|
||||||
# solana_users + blockchain_state.
|
# current user runtime-проекцию + blockchain_state.
|
||||||
# Эта настройка нужна как временный обход лимитов Solana RPC (например 429),
|
# Эта настройка нужна как временный обход лимитов Solana RPC (например 429),
|
||||||
# чтобы чистый сервер мог восстановить цепочки от партнёра без зависимости
|
# чтобы чистый сервер мог восстановить цепочки от партнёра без зависимости
|
||||||
# от внешнего Solana endpoint.
|
# от внешнего Solana endpoint.
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.354
|
client.version=1.2.354
|
||||||
server.version=1.2.335
|
server.version=1.2.336
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
Этот файл описывает раздел API, связанный с проверкой наличия пользователя на сервере и dev/test операциями.
|
Этот файл описывает раздел API, связанный с проверкой наличия пользователя на сервере и dev/test операциями.
|
||||||
|
|
||||||
Сейчас здесь три метода:
|
Сейчас здесь два метода:
|
||||||
|
|
||||||
- `AddUser` — операция отключена (регистрация только через Solana);
|
|
||||||
- `GetUser` — временная серверная проверка существования пользователя и чтение его базовых данных;
|
- `GetUser` — временная серверная проверка существования пользователя и чтение его базовых данных;
|
||||||
- `SearchUsers` — dev/test поиск логинов по префиксу.
|
- `SearchUsers` — dev/test поиск логинов по префиксу.
|
||||||
|
|
||||||
Регистрация выполняется через Solana (`shine_users`). Сервер при входе может лениво импортировать пользователя из Solana PDA в локальную БД, если записи ещё нет.
|
Регистрация выполняется только через Solana. Старый серверный `AddUser` оставлен лишь как legacy-ответ `410 / ADD_USER_DISABLED` для старых клиентов и больше не считается частью актуального flow.
|
||||||
|
|
||||||
## Статус документа
|
## Статус документа
|
||||||
|
|
||||||
@@ -18,11 +17,11 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Операция `AddUser`
|
## Legacy-операция `AddUser`
|
||||||
|
|
||||||
### Назначение
|
### Назначение
|
||||||
|
|
||||||
Операция отключена. Используется только как явный ответ клиентам старых версий.
|
Операция удалена из текущего клиентского flow. Сервер сохраняет только совместимый ответ для клиентов старых версий.
|
||||||
|
|
||||||
### Запрос
|
### Запрос
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Операция `GetUser`
|
## 1. Операция `GetUser`
|
||||||
|
|
||||||
### Назначение
|
### Назначение
|
||||||
|
|
||||||
@@ -153,7 +152,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Операция `SearchUsers`
|
## 2. Операция `SearchUsers`
|
||||||
|
|
||||||
### Назначение
|
### Назначение
|
||||||
|
|
||||||
@@ -195,7 +194,6 @@
|
|||||||
|
|
||||||
## 4. Короткое резюме
|
## 4. Короткое резюме
|
||||||
|
|
||||||
- `AddUser` — отключен (`410 / ADD_USER_DISABLED`).
|
|
||||||
- `GetUser` — проверка существования пользователя на сервере.
|
- `GetUser` — проверка существования пользователя на сервере.
|
||||||
- `SearchUsers` — временный поиск пользователей по префиксу.
|
- `SearchUsers` — временный поиск пользователей по префиксу.
|
||||||
- Регистрация выполняется только через Solana.
|
- Регистрация выполняется только через Solana.
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ AUTH_CREATE_SESSION:{login}:{sessionKey}:{storagePwd}:{timeMs}:{authNonce}
|
|||||||
|
|
||||||
Перед проверкой подписи сервер должен:
|
Перед проверкой подписи сервер должен:
|
||||||
|
|
||||||
1. взять актуальный `solana_users.client_key`;
|
1. взять актуальный `solana_user_pda_current.client_key`;
|
||||||
2. сравнить его с `payload.clientKey`;
|
2. сравнить его с `payload.clientKey`;
|
||||||
3. только потом проверять подпись.
|
3. только потом проверять подпись.
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
- `Ping` нужен для регулярной проверки, что соединение всё ещё живо;
|
- `Ping` нужен для регулярной проверки, что соединение всё ещё живо;
|
||||||
- `GetServerInfo` нужен до авторизации и до работы с данными, чтобы клиент понял, что сервер доступен, и показал пользователю краткую карточку этого узла.
|
- `GetServerInfo` нужен до авторизации и до работы с данными, чтобы клиент понял, что сервер доступен, и показал пользователю краткую карточку этого узла.
|
||||||
- `ListBlockchainHeads` нужен для сервер-сервер сверки: партнёр получает список heads по всем цепочкам, сравнивает его со своим состоянием и затем добирает недостающие блоки по диапазону.
|
- `ListBlockchainHeads` нужен для сервер-сервер сверки: партнёр получает список heads по всем цепочкам, сравнивает его со своим состоянием и затем добирает недостающие блоки по диапазону.
|
||||||
- `GetSyncUserProfile` нужен для server-to-server режима, когда принимающий сервер хочет создать у себя локальные `solana_users + blockchain_state` без прямого обращения в Solana. Это используется как временный обход ограничений внешнего Solana RPC.
|
- `GetSyncUserProfile` нужен для server-to-server режима, когда принимающий сервер хочет создать у себя локальную runtime-проекцию пользователя и `blockchain_state` без прямого обращения в Solana.
|
||||||
- `SendSignal` нужен для доверенных межсессионных команд одного пользователя. Первое практическое применение — `remote AddBlock via homeserver session`, но формат задуман как общий transport на вырост.
|
- `SendSignal` нужен для доверенных межсессионных команд одного пользователя. Первое практическое применение — `remote AddBlock via homeserver session`, но формат задуман как общий transport на вырост.
|
||||||
|
|
||||||
Ниже сначала описаны назначение методов, затем точные форматы запросов и ответов.
|
Ниже сначала описаны назначение методов, затем точные форматы запросов и ответов.
|
||||||
@@ -216,7 +216,7 @@
|
|||||||
- `clientKey`
|
- `clientKey`
|
||||||
- `blockchainSizeLimitBytes`
|
- `blockchainSizeLimitBytes`
|
||||||
|
|
||||||
После этого принимающий сервер может локально создать записи в `solana_users` и `blockchain_state`, а затем уже докачивать блоки через `GetBlockchainBlock`.
|
После этого принимающий сервер может локально создать runtime-проекцию пользователя и запись в `blockchain_state`, а затем уже докачивать блоки через `GetBlockchainBlock`.
|
||||||
|
|
||||||
Этот запрос доступен без авторизации и предназначен именно для server-to-server sync.
|
Этот запрос доступен без авторизации и предназначен именно для server-to-server sync.
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
| Операция | Раздел документации | Кратко |
|
| Операция | Раздел документации | Кратко |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `AddUser` | `01_User_Registration_API.md` | отключено (`410 / ADD_USER_DISABLED`) |
|
|
||||||
| `GetUser` | `01_User_Registration_API.md` | чтение/проверка пользователя + server-состояние его блокчейна |
|
| `GetUser` | `01_User_Registration_API.md` | чтение/проверка пользователя + server-состояние его блокчейна |
|
||||||
| `SearchUsers` | `01_User_Registration_API.md` | поиск логинов по префиксу |
|
| `SearchUsers` | `01_User_Registration_API.md` | поиск логинов по префиксу |
|
||||||
| `TestGetFreeAvatarQuota` | `14_Test_Free_Avatar_Upload_API.md` | временный тестовый просмотр остатка бесплатных загрузок аватара |
|
| `TestGetFreeAvatarQuota` | `14_Test_Free_Avatar_Upload_API.md` | временный тестовый просмотр остатка бесплатных загрузок аватара |
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
- `ListBlockchainHeads` — список heads всех локальных цепочек партнёра;
|
- `ListBlockchainHeads` — список heads всех локальных цепочек партнёра;
|
||||||
- `GetBlockchainBlock` — чтение одного конкретного блока партнёра;
|
- `GetBlockchainBlock` — чтение одного конкретного блока партнёра;
|
||||||
- `GetSyncUserProfile` — минимальный профиль пользователя для локального создания `solana_users + blockchain_state` без обращения в Solana RPC.
|
- `GetSyncUserProfile` — минимальный профиль пользователя для локального создания runtime-проекции пользователя и `blockchain_state` без обращения в Solana RPC.
|
||||||
|
|
||||||
### 4.3 Как сейчас работает periodic sync
|
### 4.3 Как сейчас работает periodic sync
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
- локальное состояние;
|
- локальное состояние;
|
||||||
3. если локальная цепочка слабее, сервер по одному блоку вызывает `GetBlockchainBlock`;
|
3. если локальная цепочка слабее, сервер по одному блоку вызывает `GetBlockchainBlock`;
|
||||||
4. каждый скачанный блок локально применяется через существующий `AddBlock`;
|
4. каждый скачанный блок локально применяется через существующий `AddBlock`;
|
||||||
5. если у сервера ещё нет локальной записи пользователя/цепочки, перед этим подготавливается локальный `solana_users + blockchain_state`.
|
5. если у сервера ещё нет локальной записи пользователя/цепочки, перед этим подготавливается локальная runtime-проекция пользователя и `blockchain_state`.
|
||||||
6. если во время replay обнаруживается рассинхрон или на одинаковой высоте удалённая цепочка сильнее, запускается полный resync:
|
6. если во время replay обнаруживается рассинхрон или на одинаковой высоте удалённая цепочка сильнее, запускается полный resync:
|
||||||
- цепочка помечается in-memory как `resync in progress`;
|
- цепочка помечается in-memory как `resync in progress`;
|
||||||
- создаётся marker-file в `data/`;
|
- создаётся marker-file в `data/`;
|
||||||
@@ -110,7 +110,7 @@ Full resync запускается только тогда, когда:
|
|||||||
Важно:
|
Важно:
|
||||||
|
|
||||||
- full resync не делает умный rollback по одному блоку;
|
- full resync не делает умный rollback по одному блоку;
|
||||||
- full resync не трогает DM-таблицы и `solana_users`;
|
- full resync не трогает DM-таблицы и current users слой;
|
||||||
- висячие cross-chain ссылки считаются допустимым поведением системы.
|
- висячие cross-chain ссылки считаются допустимым поведением системы.
|
||||||
|
|
||||||
### 4.5 Как работает обычный `AddBlock` и его recovery
|
### 4.5 Как работает обычный `AddBlock` и его recovery
|
||||||
@@ -150,7 +150,7 @@ Full resync запускается только тогда, когда:
|
|||||||
|
|
||||||
- из `blockchainName` извлекался `login`;
|
- из `blockchainName` извлекался `login`;
|
||||||
- сервер вызывал import пользователя из Solana PDA;
|
- сервер вызывал import пользователя из Solana PDA;
|
||||||
- по данным PDA локально создавались `solana_users + blockchain_state`.
|
- по данным PDA локально создавались runtime-проекция пользователя и `blockchain_state`.
|
||||||
|
|
||||||
На практике это упёрлось в ограничение внешнего Solana RPC: при чистом старте и массовой подтяжке чужих цепочек сервер мог получать `HTTP 429`.
|
На практике это упёрлось в ограничение внешнего Solana RPC: при чистом старте и массовой подтяжке чужих цепочек сервер мог получать `HTTP 429`.
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ Full resync запускается только тогда, когда:
|
|||||||
- настройка `sync.importUserProfileFromPartner.enabled=true`
|
- настройка `sync.importUserProfileFromPartner.enabled=true`
|
||||||
- в этом режиме сервер **не ходит в Solana RPC** для создания локальной цепочки во время sync;
|
- в этом режиме сервер **не ходит в Solana RPC** для создания локальной цепочки во время sync;
|
||||||
- вместо этого он запрашивает у сервера-партнёра `GetSyncUserProfile` и создаёт локальную запись по данным партнёра.
|
- вместо этого он запрашивает у сервера-партнёра `GetSyncUserProfile` и создаёт локальную запись по данным партнёра.
|
||||||
- если локальный `solana_users` уже существует, sync восстанавливает только `blockchain_state` и не трогает identity-слой.
|
- если локальная runtime-проекция пользователя уже существует, sync восстанавливает только `blockchain_state` и не трогает user-layer.
|
||||||
|
|
||||||
Это временная практическая заплатка, чтобы clean-start sync не зависел от rate limit внешнего Solana endpoint.
|
Это временная практическая заплатка, чтобы clean-start sync не зависел от rate limit внешнего Solana endpoint.
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
Для DM-проверки сервер использует:
|
Для DM-проверки сервер использует:
|
||||||
|
|
||||||
- локальную `solana_users` как кэш;
|
- локальную runtime-проекцию пользователей как кэш;
|
||||||
- Solana PDA как источник истины по `clientKey` и `access_servers`.
|
- Solana PDA как источник истины по `clientKey` и `access_servers`.
|
||||||
|
|
||||||
Если нужного пользователя нет локально, сервер обязан попытаться lazy-import из Solana PDA:
|
Если нужного пользователя нет локально, сервер обязан попытаться lazy-import из Solana PDA:
|
||||||
|
|||||||
@@ -9,8 +9,4 @@ shine.db.DatabaseInitializer — проверяет наличие `db_schema_ve
|
|||||||
|
|
||||||
|
|
||||||
shine.db.entities.* — POJO-модели строк таблиц (без логики, только поля/геттеры/сеттеры + иногда удобные методы вроде getClientKeyByte()).
|
shine.db.entities.* — POJO-модели строк таблиц (без логики, только поля/геттеры/сеттеры + иногда удобные методы вроде getClientKeyByte()).
|
||||||
shine.db.dao.* — DAO по таблицам: ActiveSessionsDAO, CurrentUsersDAO, UserParamsDAO, IpGeoCacheDAO, BlockchainStateDAO, BlocksDAO; плюс “сервисные” DAO:
|
shine.db.dao.* — DAO по таблицам: ActiveSessionsDAO, CurrentUsersDAO, UserParamsDAO, IpGeoCacheDAO, BlockchainStateDAO, BlocksDAO, SignedMessagesDAO; плюс сервисные DAO под recovery/resync.
|
||||||
|
|
||||||
UserCreateDAO — атомарная регистрация пользователя в транзакции (BEGIN IMMEDIATE + rollback/commit).
|
|
||||||
// Временное runtime-решение, позволяющее регистрировать новых пользователей
|
|
||||||
// атомарно и добавляющее запись в runtime-таблицы сервера.
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ auth/ — авторизация и сессии
|
|||||||
|
|
||||||
blockchain/ — AddBlock
|
blockchain/ — AddBlock
|
||||||
|
|
||||||
tempToTest/ — AddUser (временный, потом уйдёт в блокчейн-логику)
|
tempToTest/ — временные dev/test операции (`GetUser`, `SearchUsers`)
|
||||||
|
|
||||||
ConnectionContext
|
ConnectionContext
|
||||||
Состояние одного WebSocket-подключения (login, session, authStatus).
|
Состояние одного WebSocket-подключения (login, session, authStatus).
|
||||||
|
|||||||
@@ -1037,46 +1037,15 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async registerUser(login, password) {
|
async registerUser(login, password) {
|
||||||
const cleanLogin = (login || '').trim();
|
void login;
|
||||||
if (!cleanLogin) throw new Error('Введите логин');
|
void password;
|
||||||
|
throw new Error('Серверная регистрация через AddUser удалена. Используйте регистрацию через Solana.');
|
||||||
const isFree = await this.ensureLoginFree(cleanLogin);
|
|
||||||
if (!isFree) throw new Error('Этот логин уже занят');
|
|
||||||
|
|
||||||
const keyBundle = await this.derivePasswordKeyBundle(cleanLogin, password);
|
|
||||||
const clientPair = keyBundle?.clientPair;
|
|
||||||
|
|
||||||
const addResp = await this.ws.request('AddUser', {
|
|
||||||
login: cleanLogin,
|
|
||||||
blockchainName: `${cleanLogin}-${BCH_SUFFIX}`,
|
|
||||||
solanaKey: clientPair.publicKeyB64,
|
|
||||||
blockchainKey: keyBundle.blockchainPair.publicKeyB64,
|
|
||||||
clientKey: clientPair.publicKeyB64,
|
|
||||||
bchLimit: 1000000,
|
|
||||||
});
|
|
||||||
if (addResp.status !== 200) throw opError('AddUser', addResp);
|
|
||||||
|
|
||||||
const session = await this.createAuthSession(cleanLogin, keyBundle);
|
|
||||||
return { ...session, keyBundle };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerUserWithKeyBundle(login, keyBundle) {
|
async registerUserWithKeyBundle(login, keyBundle) {
|
||||||
const cleanLogin = (login || '').trim();
|
void login;
|
||||||
if (!cleanLogin) throw new Error('Введите логин');
|
void keyBundle;
|
||||||
const clientPair = keyBundle?.clientPair;
|
throw new Error('Серверная регистрация через AddUser удалена. Используйте регистрацию через Solana.');
|
||||||
|
|
||||||
const addResp = await this.ws.request('AddUser', {
|
|
||||||
login: cleanLogin,
|
|
||||||
blockchainName: `${cleanLogin}-${BCH_SUFFIX}`,
|
|
||||||
solanaKey: clientPair.publicKeyB64,
|
|
||||||
blockchainKey: keyBundle.blockchainPair.publicKeyB64,
|
|
||||||
clientKey: clientPair.publicKeyB64,
|
|
||||||
bchLimit: 1000000,
|
|
||||||
});
|
|
||||||
if (addResp.status !== 200) throw opError('AddUser', addResp);
|
|
||||||
|
|
||||||
const session = await this.createAuthSession(cleanLogin, keyBundle);
|
|
||||||
return { ...session, keyBundle };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async createSessionForExistingUser(login, password) {
|
async createSessionForExistingUser(login, password) {
|
||||||
|
|||||||
Reference in New Issue
Block a user