Добавил запрос связей пользователя - друзей - для построения графа друзей

И тест добавил.

но тест пока не весь проходит
This commit is contained in:
AidarKC
2026-01-28 22:31:20 +03:00
parent 22fb35d1d4
commit 922c18db4b
8 changed files with 385 additions and 5 deletions
@@ -42,10 +42,14 @@ import server.logic.ws_protocol.JSON.handlers.userParams.entyties.Net_GetUserPar
import server.logic.ws_protocol.JSON.handlers.userParams.entyties.Net_ListUserParams_Request;
import server.logic.ws_protocol.JSON.handlers.userParams.entyties.Net_UpsertUserParam_Request;
// !!! подставь реальные пакеты/имена, как у тебя в проекте:
// --- subscriptions ---
//import server.logic.ws_protocol.JSON.handlers.subscriptions.Net_GetSubscribedChannels_Handler;
import server.logic.ws_protocol.JSON.handlers.subscriptions.entyties.Net_GetSubscribedChannels_Request;
// --- NEW: connections friends lists ---
import server.logic.ws_protocol.JSON.handlers.connections.Net_GetFriendsLists_Handler;
import server.logic.ws_protocol.JSON.handlers.connections.entyties.Net_GetFriendsLists_Request;
import java.util.Map;
/**
@@ -54,7 +58,6 @@ import java.util.Map;
*/
public final class JsonHandlerRegistry {
// Map.of(...) поддерживает максимум 10 пар => используем Map.ofEntries(...)
private static final Map<String, JsonMessageHandler> HANDLERS = Map.ofEntries(
Map.entry("AddUser", new Net_AddUser_Handler()),
Map.entry("GetUser", new Net_GetUser_Handler()),
@@ -76,7 +79,10 @@ public final class JsonHandlerRegistry {
// --- userParams ---
Map.entry("UpsertUserParam", new Net_UpsertUserParam_Handler()),
Map.entry("GetUserParam", new Net_GetUserParam_Handler()),
Map.entry("ListUserParams", new Net_ListUserParams_Handler())
Map.entry("ListUserParams", new Net_ListUserParams_Handler()),
// --- connections ---
Map.entry("GetFriendsLists", new Net_GetFriendsLists_Handler())
// --- subscriptions ---
// Map.entry("ListSubscribedChannels", new Net_GetSubscribedChannels_Handler())
@@ -106,7 +112,10 @@ public final class JsonHandlerRegistry {
Map.entry("ListUserParams", Net_ListUserParams_Request.class),
// --- subscriptions ---
Map.entry("ListSubscribedChannels", Net_GetSubscribedChannels_Request.class)
Map.entry("ListSubscribedChannels", Net_GetSubscribedChannels_Request.class),
// --- connections ---
Map.entry("GetFriendsLists", Net_GetFriendsLists_Request.class)
);
private JsonHandlerRegistry() { }
@@ -0,0 +1,117 @@
package server.logic.ws_protocol.JSON.handlers.connections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.handlers.connections.entyties.Net_GetFriendsLists_Request;
import server.logic.ws_protocol.JSON.handlers.connections.entyties.Net_GetFriendsLists_Response;
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
import server.logic.ws_protocol.WireCodes;
import shine.db.MsgSubType;
import shine.db.SqliteDbController;
import shine.db.dao.ConnectionsStateDAO;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
/**
* GetFriendsLists — получить 3 списка (для того что бы построить граф связей друзей пользователя):
* - out_friends: кому login поставил FRIEND
* - in_friends: кто поставил FRIEND этому login
* - mutual_friends: FRIEND в обе стороны
*
* ВАЖНО:
* - login в запросе может быть любым регистром
* - в ответе возвращаем канонический регистр (как в solana_users.login)
*
* ПРИМЕЧАНИЕ:
* Таблица пользователей тут названа "solana_users". Если у тебя иначе — поменяй SQL.
*/
public class Net_GetFriendsLists_Handler implements JsonMessageHandler {
private static final Logger log = LoggerFactory.getLogger(Net_GetFriendsLists_Handler.class);
@Override
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
Net_GetFriendsLists_Request req = (Net_GetFriendsLists_Request) baseRequest;
if (req.getLogin() == null || req.getLogin().isBlank()) {
return NetExceptionResponseFactory.error(
req,
WireCodes.Status.BAD_REQUEST,
"BAD_FIELDS",
"Некорректные поля: login"
);
}
final String loginAnyCase = req.getLogin().trim();
try {
SqliteDbController db = SqliteDbController.getInstance();
ConnectionsStateDAO dao = ConnectionsStateDAO.getInstance();
try (Connection c = db.getConnection()) {
// 1) Канонизируем login через solana_users (NOCASE)
String canonicalLogin = findCanonicalLogin(c, loginAnyCase);
if (canonicalLogin == null) {
return NetExceptionResponseFactory.error(
req,
404,
"USER_NOT_FOUND",
"Пользователь не найден"
);
}
int relType = (int) MsgSubType.CONNECTION_FRIEND;
// 2) Три списка (все логины канонические)
List<String> outFriends = dao.listOutgoingByRelTypeCanonical(c, canonicalLogin, relType);
List<String> inFriends = dao.listIncomingByRelTypeCanonical(c, canonicalLogin, relType);
List<String> mutual = dao.listMutualByRelTypeCanonical(c, canonicalLogin, relType);
Net_GetFriendsLists_Response resp = new Net_GetFriendsLists_Response();
resp.setOp(req.getOp());
resp.setRequestId(req.getRequestId());
resp.setStatus(WireCodes.Status.OK);
resp.setLogin(canonicalLogin);
resp.setOut_friends(outFriends);
resp.setIn_friends(inFriends);
resp.setMutual_friends(mutual);
return resp;
}
} catch (Exception e) {
log.error("❌ Internal error GetFriendsLists", e);
return NetExceptionResponseFactory.error(
req,
WireCodes.Status.INTERNAL_ERROR,
"INTERNAL_ERROR",
"Внутренняя ошибка сервера"
);
}
}
private String findCanonicalLogin(Connection c, String loginAnyCase) throws Exception {
String sql = """
SELECT login
FROM solana_users
WHERE login = ? COLLATE NOCASE
LIMIT 1
""";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, loginAnyCase);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
return rs.getString("login");
}
}
}
}
@@ -0,0 +1,29 @@
package server.logic.ws_protocol.JSON.handlers.connections.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Request;
/**
* Запрос GetFriendsLists — получить два списка "друзей" по connections_state.
*
* {
* "op": "GetFriendsLists",
* "requestId": "req-100",
* "payload": {
* "login": "anya"
* }
* }
*
* Возвращает:
* - out_friends: кому login поставил FRIEND
* - in_friends: кто поставил FRIEND этому login
*
* ПРО ДОСТУП (на будущее):
* Сейчас (MVP) без ограничений. Позже можно ограничить видимость связей.
*/
public class Net_GetFriendsLists_Request extends Net_Request {
private String login;
public String getLogin() { return login; }
public void setLogin(String login) { this.login = login; }
}
@@ -0,0 +1,42 @@
package server.logic.ws_protocol.JSON.handlers.connections.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Response;
import java.util.ArrayList;
import java.util.List;
/**
* Ответ GetFriendsLists.
*
* {
* "op": "GetFriendsLists",
* "requestId": "req-100",
* "status": 200,
* "payload": {
* "login": "Anya", // канонический регистр из БД
* "out_friends": ["Bob", "Kate"], // кому login поставил FRIEND
* "in_friends": ["Alex", "Kate"], // кто поставил FRIEND login
* "mutual_friends": ["Kate"] // взаимные (два направления)
* }
* }
*/
public class Net_GetFriendsLists_Response extends Net_Response {
private String login;
private List<String> out_friends = new ArrayList<>();
private List<String> in_friends = new ArrayList<>();
private List<String> mutual_friends = new ArrayList<>();
public String getLogin() { return login; }
public void setLogin(String login) { this.login = login; }
public List<String> getOut_friends() { return out_friends; }
public void setOut_friends(List<String> out_friends) { this.out_friends = out_friends; }
public List<String> getIn_friends() { return in_friends; }
public void setIn_friends(List<String> in_friends) { this.in_friends = in_friends; }
public List<String> getMutual_friends() { return mutual_friends; }
public void setMutual_friends(List<String> mutual_friends) { this.mutual_friends = mutual_friends; }
}