Добавить ListBlockchainHeads для межсерверной сверки

This commit is contained in:
AidarKC
2026-06-25 17:52:04 +04:00
parent f0e1ab3af8
commit 1f8b20a7d1
8 changed files with 229 additions and 8 deletions
@@ -4,6 +4,8 @@ import shine.db.SqliteDbController;
import shine.db.entities.BlockchainStateEntry;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public final class BlockchainStateDAO {
@@ -53,6 +55,39 @@ public final class BlockchainStateDAO {
}
}
/** Получить все blockchain_state записи. */
public List<BlockchainStateEntry> listAll() throws SQLException {
try (Connection c = db.getConnection()) {
return listAll(c);
}
}
/** Получить все blockchain_state записи с внешним соединением. Соединение НЕ закрывает. */
public List<BlockchainStateEntry> listAll(Connection c) throws SQLException {
String sql = """
SELECT
blockchain_name,
login,
blockchain_key,
size_limit,
file_size_bytes,
last_block_number,
last_block_hash,
updated_at_ms
FROM blockchain_state
ORDER BY blockchain_name COLLATE NOCASE
""";
List<BlockchainStateEntry> result = new ArrayList<>();
try (PreparedStatement ps = c.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
result.add(mapRow(rs));
}
}
return result;
}
/** UPSERT без внешнего соединения. Сам открывает/закрывает. */
public void upsert(BlockchainStateEntry e) throws SQLException {
try (Connection c = db.getConnection()) {
@@ -150,4 +185,4 @@ public final class BlockchainStateDAO {
}
private static String nn(String s) { return s == null ? "" : s; }
}
}
@@ -106,6 +106,7 @@ import server.logic.ws_protocol.JSON.handlers.system.Net_GetServerInfo_Handler;
import server.logic.ws_protocol.JSON.handlers.system.Net_GetCallIceConfig_Handler;
import server.logic.ws_protocol.JSON.handlers.system.Net_ClientErrorLog_Handler;
import server.logic.ws_protocol.JSON.handlers.system.Net_ClientDebugLog_Handler;
import server.logic.ws_protocol.JSON.handlers.system.Net_ListBlockchainHeads_Handler;
import server.logic.ws_protocol.JSON.handlers.system.Net_CallDeliveryReport_Handler;
import server.logic.ws_protocol.JSON.handlers.system.Net_Ping_Handler;
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_CallDeliveryReport_Request;
@@ -113,6 +114,7 @@ import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ClientErrorLog
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ClientDebugLog_Request;
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_GetCallIceConfig_Request;
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_GetServerInfo_Request;
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ListBlockchainHeads_Request;
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_Ping_Request;
import java.util.Map;
@@ -193,6 +195,7 @@ public final class JsonHandlerRegistry {
// --- system ---
Map.entry("Ping", new Net_Ping_Handler()),
Map.entry("GetServerInfo", new Net_GetServerInfo_Handler()),
Map.entry("ListBlockchainHeads", new Net_ListBlockchainHeads_Handler()),
Map.entry("GetCallIceConfig", new Net_GetCallIceConfig_Handler()),
Map.entry("ClientErrorLog", new Net_ClientErrorLog_Handler()),
Map.entry("ClientDebugLog", new Net_ClientDebugLog_Handler()),
@@ -268,6 +271,7 @@ public final class JsonHandlerRegistry {
// --- system ---
Map.entry("Ping", Net_Ping_Request.class),
Map.entry("GetServerInfo", Net_GetServerInfo_Request.class),
Map.entry("ListBlockchainHeads", Net_ListBlockchainHeads_Request.class),
Map.entry("GetCallIceConfig", Net_GetCallIceConfig_Request.class),
Map.entry("ClientErrorLog", Net_ClientErrorLog_Request.class),
Map.entry("ClientDebugLog", Net_ClientDebugLog_Request.class),
@@ -0,0 +1,76 @@
package server.logic.ws_protocol.JSON.handlers.system;
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.system.entyties.Net_ListBlockchainHeads_Request;
import server.logic.ws_protocol.JSON.handlers.system.entyties.Net_ListBlockchainHeads_Response;
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
import server.logic.ws_protocol.WireCodes;
import shine.db.dao.BlockchainStateDAO;
import shine.db.entities.BlockchainStateEntry;
import java.util.ArrayList;
import java.util.List;
/**
* ListBlockchainHeads — получить краткую сводку по всем blockchain_state.
* Используется для межсерверной сверки heads перед догоняющей синхронизацией.
*/
public class Net_ListBlockchainHeads_Handler implements JsonMessageHandler {
private static final Logger log = LoggerFactory.getLogger(Net_ListBlockchainHeads_Handler.class);
@Override
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) {
Net_ListBlockchainHeads_Request req = (Net_ListBlockchainHeads_Request) baseRequest;
try {
List<BlockchainStateEntry> states = BlockchainStateDAO.getInstance().listAll();
Net_ListBlockchainHeads_Response resp = new Net_ListBlockchainHeads_Response();
resp.setOp(req.getOp());
resp.setRequestId(req.getRequestId());
resp.setStatus(WireCodes.Status.OK);
List<Net_ListBlockchainHeads_Response.Item> items = new ArrayList<>(states.size());
for (BlockchainStateEntry state : states) {
Net_ListBlockchainHeads_Response.Item item = new Net_ListBlockchainHeads_Response.Item();
item.setBlockchainName(state.getBlockchainName());
item.setLastBlockNumber(state.getLastBlockNumber());
item.setLastBlockHash(toHex32(state.getLastBlockHash()));
item.setFileSizeBytes(state.getFileSizeBytes());
items.add(item);
}
resp.setBlockchains(items);
return resp;
} catch (Exception e) {
log.error("❌ Internal error ListBlockchainHeads", e);
return NetExceptionResponseFactory.error(
req,
WireCodes.Status.INTERNAL_ERROR,
"INTERNAL_ERROR",
NetExceptionResponseFactory.detailedMessage("Внутренняя ошибка сервера при ListBlockchainHeads", e)
);
}
}
private static String toHex32(byte[] bytes32) {
byte[] b = bytes32;
if (b == null || b.length != 32) {
b = new byte[32];
}
final char[] hex = "0123456789abcdef".toCharArray();
char[] out = new char[64];
for (int i = 0; i < 32; i++) {
int v = b[i] & 0xFF;
out[i * 2] = hex[v >>> 4];
out[i * 2 + 1] = hex[v & 0x0F];
}
return new String(out);
}
}
@@ -0,0 +1,9 @@
package server.logic.ws_protocol.JSON.handlers.system.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Request;
/**
* Пустой запрос для получения списка heads всех blockchain_state.
*/
public class Net_ListBlockchainHeads_Request extends Net_Request {
}
@@ -0,0 +1,33 @@
package server.logic.ws_protocol.JSON.handlers.system.entyties;
import server.logic.ws_protocol.JSON.entyties.Net_Response;
import java.util.ArrayList;
import java.util.List;
public class Net_ListBlockchainHeads_Response extends Net_Response {
public static final class Item {
private String blockchainName;
private int lastBlockNumber;
private String lastBlockHash;
private long fileSizeBytes;
public String getBlockchainName() { return blockchainName; }
public void setBlockchainName(String blockchainName) { this.blockchainName = blockchainName; }
public int getLastBlockNumber() { return lastBlockNumber; }
public void setLastBlockNumber(int lastBlockNumber) { this.lastBlockNumber = lastBlockNumber; }
public String getLastBlockHash() { return lastBlockHash; }
public void setLastBlockHash(String lastBlockHash) { this.lastBlockHash = lastBlockHash; }
public long getFileSizeBytes() { return fileSizeBytes; }
public void setFileSizeBytes(long fileSizeBytes) { this.fileSizeBytes = fileSizeBytes; }
}
private List<Item> blockchains = new ArrayList<>();
public List<Item> getBlockchains() { return blockchains; }
public void setBlockchains(List<Item> blockchains) { this.blockchains = blockchains; }
}