SHA256
Обновить синхронизацию серверов и экран сохранения ключей
This commit is contained in:
@@ -14,7 +14,7 @@ import java.sql.Statement;
|
||||
public final class SqliteDbController {
|
||||
|
||||
private static volatile SqliteDbController instance;
|
||||
private static final int LATEST_SCHEMA_VERSION = 8;
|
||||
private static final int LATEST_SCHEMA_VERSION = 9;
|
||||
|
||||
private final String jdbcUrl;
|
||||
|
||||
@@ -91,6 +91,7 @@ public final class SqliteDbController {
|
||||
case 6 -> migrateToV6();
|
||||
case 7 -> migrateToV7();
|
||||
case 8 -> migrateToV8();
|
||||
case 9 -> migrateToV9();
|
||||
default -> throw new RuntimeException("Unknown DB migration target version: " + targetVersion);
|
||||
}
|
||||
}
|
||||
@@ -269,6 +270,25 @@ public final class SqliteDbController {
|
||||
}
|
||||
}
|
||||
|
||||
private void migrateToV9() {
|
||||
try (Connection c = DriverManager.getConnection(jdbcUrl);
|
||||
Statement st = c.createStatement()) {
|
||||
c.setAutoCommit(false);
|
||||
try {
|
||||
ensureSyncServersTable(st);
|
||||
setSchemaVersion(c, 9);
|
||||
c.commit();
|
||||
} catch (Exception e) {
|
||||
try { c.rollback(); } catch (Exception ignored) {}
|
||||
throw new RuntimeException("DB migration to v9 failed", e);
|
||||
} finally {
|
||||
try { c.setAutoCommit(true); } catch (Exception ignored) {}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("DB migration to v9 failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureChat200StateTables(Statement st) throws SQLException {
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS chat200_state (
|
||||
@@ -468,6 +488,20 @@ public final class SqliteDbController {
|
||||
""");
|
||||
}
|
||||
|
||||
private static void ensureSyncServersTable(Statement st) throws SQLException {
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS sync_servers (
|
||||
login TEXT NOT NULL PRIMARY KEY COLLATE NOCASE,
|
||||
server_address TEXT NOT NULL DEFAULT '',
|
||||
updated_at_ms INTEGER NOT NULL
|
||||
);
|
||||
""");
|
||||
st.executeUpdate("""
|
||||
CREATE INDEX IF NOT EXISTS idx_sync_servers_updated
|
||||
ON sync_servers (updated_at_ms);
|
||||
""");
|
||||
}
|
||||
|
||||
|
||||
private static void createConnectionsStateTable(Statement st) throws SQLException {
|
||||
st.executeUpdate("""
|
||||
|
||||
@@ -6,6 +6,8 @@ import shine.db.SqliteDbController;
|
||||
import shine.db.entities.BlockEntry;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DAO для таблицы blocks (новый формат).
|
||||
@@ -191,6 +193,53 @@ public final class BlocksDAO {
|
||||
}
|
||||
}
|
||||
|
||||
public List<BlockEntry> listRangeByNumber(String bchName, int fromBlockNumberInclusive, int toBlockNumberInclusive) throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
return listRangeByNumber(c, bchName, fromBlockNumberInclusive, toBlockNumberInclusive);
|
||||
}
|
||||
}
|
||||
|
||||
public List<BlockEntry> listRangeByNumber(Connection c, String bchName, int fromBlockNumberInclusive, int toBlockNumberInclusive) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
login,
|
||||
bch_name,
|
||||
block_number,
|
||||
msg_type,
|
||||
msg_sub_type,
|
||||
block_bytes,
|
||||
to_login,
|
||||
to_bch_name,
|
||||
to_block_number,
|
||||
to_block_hash,
|
||||
block_hash,
|
||||
block_signature,
|
||||
edited_by_block_number,
|
||||
line_code,
|
||||
prev_line_number,
|
||||
prev_line_hash,
|
||||
this_line_number
|
||||
FROM blocks
|
||||
WHERE bch_name = ?
|
||||
AND block_number >= ?
|
||||
AND block_number <= ?
|
||||
ORDER BY block_number ASC
|
||||
""";
|
||||
|
||||
List<BlockEntry> result = new ArrayList<>();
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
ps.setString(1, bchName);
|
||||
ps.setInt(2, fromBlockNumberInclusive);
|
||||
ps.setInt(3, toBlockNumberInclusive);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
result.add(mapRow(rs));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------- INTERNAL --------------------
|
||||
|
||||
private BlockEntry mapRow(ResultSet rs) throws SQLException {
|
||||
@@ -242,4 +291,4 @@ public final class BlocksDAO {
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package shine.db.dao;
|
||||
|
||||
import shine.db.SqliteDbController;
|
||||
import shine.db.entities.SyncServerEntry;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DAO локальной таблицы серверов-партнёров для будущей межсерверной синхронизации.
|
||||
*/
|
||||
public final class SyncServersDAO {
|
||||
|
||||
private static volatile SyncServersDAO instance;
|
||||
private final SqliteDbController db = SqliteDbController.getInstance();
|
||||
|
||||
private SyncServersDAO() {}
|
||||
|
||||
public static SyncServersDAO getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (SyncServersDAO.class) {
|
||||
if (instance == null) instance = new SyncServersDAO();
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public List<SyncServerEntry> listAll() throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
return listAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SyncServerEntry> listAll(Connection c) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, server_address, updated_at_ms
|
||||
FROM sync_servers
|
||||
ORDER BY login
|
||||
""";
|
||||
List<SyncServerEntry> result = new ArrayList<>();
|
||||
try (PreparedStatement ps = c.prepareStatement(sql);
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
result.add(mapRow(rs));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Полностью заменяет список партнёров актуальным снимком из Solana PDA.
|
||||
*/
|
||||
public void replaceAll(List<SyncServerEntry> entries) throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
replaceAll(c, entries);
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceAll(Connection c, List<SyncServerEntry> entries) throws SQLException {
|
||||
boolean oldAutoCommit = c.getAutoCommit();
|
||||
c.setAutoCommit(false);
|
||||
try (Statement st = c.createStatement()) {
|
||||
st.executeUpdate("DELETE FROM sync_servers");
|
||||
String sql = """
|
||||
INSERT INTO sync_servers (
|
||||
login, server_address, updated_at_ms
|
||||
) VALUES (?, ?, ?)
|
||||
""";
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
for (SyncServerEntry entry : entries) {
|
||||
ps.setString(1, entry.getLogin());
|
||||
ps.setString(2, safe(entry.getServerAddress()));
|
||||
ps.setLong(3, entry.getUpdatedAtMs());
|
||||
ps.addBatch();
|
||||
}
|
||||
ps.executeBatch();
|
||||
}
|
||||
c.commit();
|
||||
} catch (Exception e) {
|
||||
try { c.rollback(); } catch (Exception ignored) {}
|
||||
if (e instanceof SQLException sqlEx) throw sqlEx;
|
||||
throw new SQLException("Не удалось обновить таблицу sync_servers", e);
|
||||
} finally {
|
||||
try { c.setAutoCommit(oldAutoCommit); } catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private SyncServerEntry mapRow(ResultSet rs) throws SQLException {
|
||||
SyncServerEntry entry = new SyncServerEntry();
|
||||
entry.setLogin(rs.getString("login"));
|
||||
entry.setServerAddress(rs.getString("server_address"));
|
||||
entry.setUpdatedAtMs(rs.getLong("updated_at_ms"));
|
||||
return entry;
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package shine.db.entities;
|
||||
|
||||
/**
|
||||
* Запись о сервере-партнёре, с которым текущий сервер должен синхронизироваться.
|
||||
*/
|
||||
public class SyncServerEntry {
|
||||
|
||||
private String login;
|
||||
private String serverAddress;
|
||||
private long updatedAtMs;
|
||||
|
||||
public SyncServerEntry() {}
|
||||
|
||||
public SyncServerEntry(String login, String serverAddress, long updatedAtMs) {
|
||||
this.login = login;
|
||||
this.serverAddress = serverAddress;
|
||||
this.updatedAtMs = updatedAtMs;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
public String getServerAddress() {
|
||||
return serverAddress;
|
||||
}
|
||||
|
||||
public void setServerAddress(String serverAddress) {
|
||||
this.serverAddress = serverAddress;
|
||||
}
|
||||
|
||||
public long getUpdatedAtMs() {
|
||||
return updatedAtMs;
|
||||
}
|
||||
|
||||
public void setUpdatedAtMs(long updatedAtMs) {
|
||||
this.updatedAtMs = updatedAtMs;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user