SHA256
05 01 25
поменял все названия таблиц и полей в таблицах на стиль только маленькие буквы и разделение через "_" . Все тесты проходят норм
This commit is contained in:
@@ -21,8 +21,8 @@ import java.sql.Statement;
|
||||
* - ip_geo_cache
|
||||
* - blockchain_state
|
||||
* - blocks
|
||||
* - connections_state (текущее состояние связей)
|
||||
* - message_stats (счётчики лайков/ответов на сообщения)
|
||||
* - connections_state
|
||||
* - message_stats
|
||||
*/
|
||||
public class DatabaseInitializer {
|
||||
|
||||
@@ -83,8 +83,8 @@ public class DatabaseInitializer {
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS solana_users (
|
||||
login TEXT NOT NULL PRIMARY KEY,
|
||||
deviceKey TEXT NOT NULL,
|
||||
solanaKey TEXT
|
||||
device_key TEXT NOT NULL,
|
||||
solana_key TEXT
|
||||
);
|
||||
""");
|
||||
|
||||
@@ -96,19 +96,19 @@ public class DatabaseInitializer {
|
||||
// 2. active_sessions
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS active_sessions (
|
||||
sessionId TEXT NOT NULL PRIMARY KEY,
|
||||
login TEXT NOT NULL,
|
||||
sessionPwd TEXT NOT NULL,
|
||||
storagePwd TEXT NOT NULL,
|
||||
sessionCreatedAtMs INTEGER NOT NULL,
|
||||
lastAuthirificatedAtMs INTEGER NOT NULL,
|
||||
pushEndpoint TEXT,
|
||||
pushP256dhKey TEXT,
|
||||
pushAuthKey TEXT,
|
||||
clientIp TEXT,
|
||||
clientInfoFromClient TEXT,
|
||||
clientInfoFromRequest TEXT,
|
||||
userLanguage TEXT,
|
||||
session_id TEXT NOT NULL PRIMARY KEY,
|
||||
login TEXT NOT NULL,
|
||||
session_pwd TEXT NOT NULL,
|
||||
storage_pwd TEXT NOT NULL,
|
||||
session_created_at_ms INTEGER NOT NULL,
|
||||
last_authirificated_at_ms INTEGER NOT NULL,
|
||||
push_endpoint TEXT,
|
||||
push_p256dh_key TEXT,
|
||||
push_auth_key TEXT,
|
||||
client_ip TEXT,
|
||||
client_info_from_client TEXT,
|
||||
client_info_from_request TEXT,
|
||||
user_language TEXT,
|
||||
FOREIGN KEY (login) REFERENCES solana_users(login)
|
||||
);
|
||||
""");
|
||||
@@ -154,33 +154,33 @@ public class DatabaseInitializer {
|
||||
// 5. blockchain_state
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS blockchain_state (
|
||||
blockchainName TEXT NOT NULL PRIMARY KEY,
|
||||
login TEXT NOT NULL,
|
||||
blockchainKey TEXT NOT NULL,
|
||||
blockchain_name TEXT NOT NULL PRIMARY KEY,
|
||||
login TEXT NOT NULL,
|
||||
blockchain_key TEXT NOT NULL,
|
||||
|
||||
size_limit INTEGER NOT NULL,
|
||||
file_size_bytes INTEGER NOT NULL,
|
||||
size_limit INTEGER NOT NULL,
|
||||
file_size_bytes INTEGER NOT NULL,
|
||||
|
||||
last_global_number INTEGER NOT NULL,
|
||||
last_global_hash TEXT NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
last_global_number INTEGER NOT NULL,
|
||||
last_global_hash TEXT NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL,
|
||||
|
||||
line0_last_number INTEGER NOT NULL,
|
||||
line0_last_hash TEXT NOT NULL,
|
||||
line1_last_number INTEGER NOT NULL,
|
||||
line1_last_hash TEXT NOT NULL,
|
||||
line2_last_number INTEGER NOT NULL,
|
||||
line2_last_hash TEXT NOT NULL,
|
||||
line3_last_number INTEGER NOT NULL,
|
||||
line3_last_hash TEXT NOT NULL,
|
||||
line4_last_number INTEGER NOT NULL,
|
||||
line4_last_hash TEXT NOT NULL,
|
||||
line5_last_number INTEGER NOT NULL,
|
||||
line5_last_hash TEXT NOT NULL,
|
||||
line6_last_number INTEGER NOT NULL,
|
||||
line6_last_hash TEXT NOT NULL,
|
||||
line7_last_number INTEGER NOT NULL,
|
||||
line7_last_hash TEXT NOT NULL,
|
||||
line0_last_number INTEGER NOT NULL,
|
||||
line0_last_hash TEXT NOT NULL,
|
||||
line1_last_number INTEGER NOT NULL,
|
||||
line1_last_hash TEXT NOT NULL,
|
||||
line2_last_number INTEGER NOT NULL,
|
||||
line2_last_hash TEXT NOT NULL,
|
||||
line3_last_number INTEGER NOT NULL,
|
||||
line3_last_hash TEXT NOT NULL,
|
||||
line4_last_number INTEGER NOT NULL,
|
||||
line4_last_hash TEXT NOT NULL,
|
||||
line5_last_number INTEGER NOT NULL,
|
||||
line5_last_hash TEXT NOT NULL,
|
||||
line6_last_number INTEGER NOT NULL,
|
||||
line6_last_hash TEXT NOT NULL,
|
||||
line7_last_number INTEGER NOT NULL,
|
||||
line7_last_hash TEXT NOT NULL,
|
||||
|
||||
FOREIGN KEY (login) REFERENCES solana_users(login)
|
||||
);
|
||||
@@ -199,55 +199,53 @@ public class DatabaseInitializer {
|
||||
// 6. blocks
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS blocks (
|
||||
login TEXT NOT NULL,
|
||||
bchName TEXT NOT NULL,
|
||||
blockGlobalNumber INTEGER NOT NULL,
|
||||
blockGlobalPreHashe TEXT NOT NULL,
|
||||
login TEXT NOT NULL,
|
||||
bch_name TEXT NOT NULL,
|
||||
block_global_number INTEGER NOT NULL,
|
||||
block_global_pre_hashe TEXT NOT NULL,
|
||||
|
||||
blockLineIndex INTEGER NOT NULL,
|
||||
blockLineNumber INTEGER NOT NULL,
|
||||
blockLinePreHashe TEXT NOT NULL,
|
||||
block_line_index INTEGER NOT NULL,
|
||||
block_line_number INTEGER NOT NULL,
|
||||
block_line_pre_hashe TEXT NOT NULL,
|
||||
|
||||
msgType INTEGER NOT NULL,
|
||||
msgSubType INTEGER NOT NULL,
|
||||
msg_type INTEGER NOT NULL,
|
||||
msg_sub_type INTEGER NOT NULL,
|
||||
|
||||
blockByte BLOB,
|
||||
block_byte BLOB,
|
||||
|
||||
to_login TEXT,
|
||||
toBchName TEXT,
|
||||
toBlockGlobalNumber INTEGER,
|
||||
toBlockHashe TEXT,
|
||||
to_login TEXT,
|
||||
to_bch_name TEXT,
|
||||
to_block_global_number INTEGER,
|
||||
to_block_hashe TEXT,
|
||||
|
||||
FOREIGN KEY (login) REFERENCES solana_users(login),
|
||||
FOREIGN KEY (bchName) REFERENCES blockchain_state(blockchainName)
|
||||
FOREIGN KEY (bch_name) REFERENCES blockchain_state(blockchain_name)
|
||||
);
|
||||
""");
|
||||
|
||||
st.executeUpdate("""
|
||||
CREATE INDEX IF NOT EXISTS idx_blocks_chain_global
|
||||
ON blocks (login, bchName, blockGlobalNumber);
|
||||
ON blocks (login, bch_name, block_global_number);
|
||||
""");
|
||||
|
||||
st.executeUpdate("""
|
||||
CREATE INDEX IF NOT EXISTS idx_blocks_to_target
|
||||
ON blocks (to_login, toBchName, toBlockGlobalNumber);
|
||||
ON blocks (to_login, to_bch_name, to_block_global_number);
|
||||
""");
|
||||
|
||||
// =====================================================================
|
||||
// 7) connections_state — текущее состояние "кто с кем и какая связь"
|
||||
// =====================================================================
|
||||
// 7) connections_state
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS connections_state (
|
||||
login TEXT NOT NULL,
|
||||
relType INTEGER NOT NULL, -- 10/20/30 (FRIEND/CONTACT/FOLLOW)
|
||||
to_login TEXT NOT NULL,
|
||||
toBchName TEXT NOT NULL,
|
||||
toBlockGlobalNumber INTEGER,
|
||||
toBlockHashe TEXT,
|
||||
login TEXT NOT NULL,
|
||||
rel_type INTEGER NOT NULL,
|
||||
to_login TEXT NOT NULL,
|
||||
to_bch_name TEXT NOT NULL,
|
||||
to_block_global_number INTEGER,
|
||||
to_block_hashe TEXT,
|
||||
|
||||
FOREIGN KEY (login) REFERENCES solana_users(login),
|
||||
|
||||
UNIQUE (login, relType, to_login)
|
||||
UNIQUE (login, rel_type, to_login)
|
||||
);
|
||||
""");
|
||||
|
||||
@@ -266,54 +264,47 @@ public class DatabaseInitializer {
|
||||
ON connections_state (login, to_login);
|
||||
""");
|
||||
|
||||
// =====================================================================
|
||||
// 8) Trigger: при вставке connection-блоков в blocks — обновлять connections_state
|
||||
// =====================================================================
|
||||
// 8) Trigger: connection state
|
||||
st.executeUpdate("""
|
||||
CREATE TRIGGER IF NOT EXISTS trg_blocks_connection_state_ai
|
||||
AFTER INSERT ON blocks
|
||||
WHEN NEW.msgType = 3
|
||||
WHEN NEW.msg_type = 3
|
||||
BEGIN
|
||||
|
||||
INSERT INTO connections_state (
|
||||
login, relType, to_login, toBchName, toBlockGlobalNumber, toBlockHashe
|
||||
login, rel_type, to_login, to_bch_name, to_block_global_number, to_block_hashe
|
||||
)
|
||||
SELECT
|
||||
NEW.login,
|
||||
NEW.msgSubType,
|
||||
NEW.msg_sub_type,
|
||||
NEW.to_login,
|
||||
NEW.toBchName,
|
||||
NEW.toBlockGlobalNumber,
|
||||
NEW.toBlockHashe
|
||||
WHERE NEW.msgSubType IN (10, 20, 30)
|
||||
NEW.to_bch_name,
|
||||
NEW.to_block_global_number,
|
||||
NEW.to_block_hashe
|
||||
WHERE NEW.msg_sub_type IN (10, 20, 30)
|
||||
AND NEW.to_login IS NOT NULL
|
||||
AND NEW.toBchName IS NOT NULL
|
||||
ON CONFLICT(login, relType, to_login)
|
||||
AND NEW.to_bch_name IS NOT NULL
|
||||
ON CONFLICT(login, rel_type, to_login)
|
||||
DO UPDATE SET
|
||||
toBchName = excluded.toBchName,
|
||||
toBlockGlobalNumber = excluded.toBlockGlobalNumber,
|
||||
toBlockHashe = excluded.toBlockHashe;
|
||||
to_bch_name = excluded.to_bch_name,
|
||||
to_block_global_number = excluded.to_block_global_number,
|
||||
to_block_hashe = excluded.to_block_hashe;
|
||||
|
||||
DELETE FROM connections_state
|
||||
WHERE login = NEW.login
|
||||
AND to_login = NEW.to_login
|
||||
AND relType = CASE NEW.msgSubType
|
||||
AND rel_type = CASE NEW.msg_sub_type
|
||||
WHEN 11 THEN 10
|
||||
WHEN 21 THEN 20
|
||||
WHEN 31 THEN 30
|
||||
ELSE relType
|
||||
ELSE rel_type
|
||||
END
|
||||
AND NEW.msgSubType IN (11, 21, 31);
|
||||
AND NEW.msg_sub_type IN (11, 21, 31);
|
||||
|
||||
END;
|
||||
""");
|
||||
|
||||
// =====================================================================
|
||||
// 9) message_stats — счётчики лайков/ответов на конкретный блок-цель
|
||||
//
|
||||
// Правило системы:
|
||||
// - to_login берём из toBchName: отрезаем последние 3 символа
|
||||
// =====================================================================
|
||||
// 9) message_stats
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS message_stats (
|
||||
to_login TEXT NOT NULL,
|
||||
@@ -343,15 +334,11 @@ public class DatabaseInitializer {
|
||||
ON message_stats (to_login);
|
||||
""");
|
||||
|
||||
// =====================================================================
|
||||
// 10) Trigger: LIKE (Reaction)
|
||||
// - msgType=2 (REACTION)
|
||||
// - msgSubType=1 (LIKE)
|
||||
// =====================================================================
|
||||
// 10) Trigger: LIKE
|
||||
st.executeUpdate("""
|
||||
CREATE TRIGGER IF NOT EXISTS trg_blocks_message_stats_like_ai
|
||||
AFTER INSERT ON blocks
|
||||
WHEN NEW.msgType = 2 AND NEW.msgSubType = 1
|
||||
WHEN NEW.msg_type = 2 AND NEW.msg_sub_type = 1
|
||||
BEGIN
|
||||
INSERT INTO message_stats (
|
||||
to_login,
|
||||
@@ -362,31 +349,27 @@ public class DatabaseInitializer {
|
||||
replies_count
|
||||
)
|
||||
SELECT
|
||||
substr(NEW.toBchName, 1, length(NEW.toBchName) - 3),
|
||||
NEW.toBchName,
|
||||
NEW.toBlockGlobalNumber,
|
||||
NEW.toBlockHashe,
|
||||
substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 3),
|
||||
NEW.to_bch_name,
|
||||
NEW.to_block_global_number,
|
||||
NEW.to_block_hashe,
|
||||
1,
|
||||
0
|
||||
WHERE NEW.toBchName IS NOT NULL
|
||||
AND length(NEW.toBchName) > 3
|
||||
AND NEW.toBlockGlobalNumber IS NOT NULL
|
||||
AND NEW.toBlockHashe IS NOT NULL
|
||||
WHERE NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 3
|
||||
AND NEW.to_block_global_number IS NOT NULL
|
||||
AND NEW.to_block_hashe IS NOT NULL
|
||||
ON CONFLICT(to_login, to_bch_name, to_block_global_number, to_block_hash)
|
||||
DO UPDATE SET
|
||||
likes_count = message_stats.likes_count + 1;
|
||||
END;
|
||||
""");
|
||||
|
||||
// =====================================================================
|
||||
// 11) Trigger: REPLY (Text)
|
||||
// - msgType=1 (TEXT)
|
||||
// - msgSubType=2 (REPLY)
|
||||
// =====================================================================
|
||||
// 11) Trigger: REPLY
|
||||
st.executeUpdate("""
|
||||
CREATE TRIGGER IF NOT EXISTS trg_blocks_message_stats_reply_ai
|
||||
AFTER INSERT ON blocks
|
||||
WHEN NEW.msgType = 1 AND NEW.msgSubType = 2
|
||||
WHEN NEW.msg_type = 1 AND NEW.msg_sub_type = 2
|
||||
BEGIN
|
||||
INSERT INTO message_stats (
|
||||
to_login,
|
||||
@@ -397,16 +380,16 @@ public class DatabaseInitializer {
|
||||
replies_count
|
||||
)
|
||||
SELECT
|
||||
substr(NEW.toBchName, 1, length(NEW.toBchName) - 3),
|
||||
NEW.toBchName,
|
||||
NEW.toBlockGlobalNumber,
|
||||
NEW.toBlockHashe,
|
||||
substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 3),
|
||||
NEW.to_bch_name,
|
||||
NEW.to_block_global_number,
|
||||
NEW.to_block_hashe,
|
||||
0,
|
||||
1
|
||||
WHERE NEW.toBchName IS NOT NULL
|
||||
AND length(NEW.toBchName) > 3
|
||||
AND NEW.toBlockGlobalNumber IS NOT NULL
|
||||
AND NEW.toBlockHashe IS NOT NULL
|
||||
WHERE NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 3
|
||||
AND NEW.to_block_global_number IS NOT NULL
|
||||
AND NEW.to_block_hashe IS NOT NULL
|
||||
ON CONFLICT(to_login, to_bch_name, to_block_global_number, to_block_hash)
|
||||
DO UPDATE SET
|
||||
replies_count = message_stats.replies_count + 1;
|
||||
|
||||
@@ -50,10 +50,6 @@ public final class SqliteDbController {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Каждый вызов возвращает НОВОЕ соединение.
|
||||
* Закрывать обязан вызывающий код (try-with-resources).
|
||||
*/
|
||||
public Connection getConnection() throws SQLException {
|
||||
Connection conn = DriverManager.getConnection(jdbcUrl);
|
||||
conn.setAutoCommit(true);
|
||||
@@ -68,7 +64,6 @@ public final class SqliteDbController {
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** Теперь close() не нужен. */
|
||||
public void close() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@@ -36,19 +36,19 @@ public final class ActiveSessionsDAO {
|
||||
public void insert(Connection c, ActiveSessionEntry session) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO active_sessions (
|
||||
sessionId,
|
||||
session_id,
|
||||
login,
|
||||
sessionPwd,
|
||||
storagePwd,
|
||||
sessionCreatedAtMs,
|
||||
lastAuthirificatedAtMs,
|
||||
pushEndpoint,
|
||||
pushP256dhKey,
|
||||
pushAuthKey,
|
||||
clientIp,
|
||||
clientInfoFromClient,
|
||||
clientInfoFromRequest,
|
||||
userLanguage
|
||||
session_pwd,
|
||||
storage_pwd,
|
||||
session_created_at_ms,
|
||||
last_authirificated_at_ms,
|
||||
push_endpoint,
|
||||
push_p256dh_key,
|
||||
push_auth_key,
|
||||
client_ip,
|
||||
client_info_from_client,
|
||||
client_info_from_request,
|
||||
user_language
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
@@ -83,21 +83,21 @@ public final class ActiveSessionsDAO {
|
||||
public ActiveSessionEntry getBySessionId(Connection c, String sessionId) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
sessionId,
|
||||
session_id,
|
||||
login,
|
||||
sessionPwd,
|
||||
storagePwd,
|
||||
sessionCreatedAtMs,
|
||||
lastAuthirificatedAtMs,
|
||||
pushEndpoint,
|
||||
pushP256dhKey,
|
||||
pushAuthKey,
|
||||
clientIp,
|
||||
clientInfoFromClient,
|
||||
clientInfoFromRequest,
|
||||
userLanguage
|
||||
session_pwd,
|
||||
storage_pwd,
|
||||
session_created_at_ms,
|
||||
last_authirificated_at_ms,
|
||||
push_endpoint,
|
||||
push_p256dh_key,
|
||||
push_auth_key,
|
||||
client_ip,
|
||||
client_info_from_client,
|
||||
client_info_from_request,
|
||||
user_language
|
||||
FROM active_sessions
|
||||
WHERE sessionId = ?
|
||||
WHERE session_id = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
@@ -120,19 +120,19 @@ public final class ActiveSessionsDAO {
|
||||
public List<ActiveSessionEntry> getByLogin(Connection c, String login) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
sessionId,
|
||||
session_id,
|
||||
login,
|
||||
sessionPwd,
|
||||
storagePwd,
|
||||
sessionCreatedAtMs,
|
||||
lastAuthirificatedAtMs,
|
||||
pushEndpoint,
|
||||
pushP256dhKey,
|
||||
pushAuthKey,
|
||||
clientIp,
|
||||
clientInfoFromClient,
|
||||
clientInfoFromRequest,
|
||||
userLanguage
|
||||
session_pwd,
|
||||
storage_pwd,
|
||||
session_created_at_ms,
|
||||
last_authirificated_at_ms,
|
||||
push_endpoint,
|
||||
push_p256dh_key,
|
||||
push_auth_key,
|
||||
client_ip,
|
||||
client_info_from_client,
|
||||
client_info_from_request,
|
||||
user_language
|
||||
FROM active_sessions
|
||||
WHERE login = ?
|
||||
""";
|
||||
@@ -162,8 +162,8 @@ public final class ActiveSessionsDAO {
|
||||
public void updateLastAuthirificatedAtMs(Connection c, String sessionId, long lastAuthMs) throws SQLException {
|
||||
String sql = """
|
||||
UPDATE active_sessions
|
||||
SET lastAuthirificatedAtMs = ?
|
||||
WHERE sessionId = ?
|
||||
SET last_authirificated_at_ms = ?
|
||||
WHERE session_id = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
@@ -194,12 +194,12 @@ public final class ActiveSessionsDAO {
|
||||
String sql = """
|
||||
UPDATE active_sessions
|
||||
SET
|
||||
lastAuthirificatedAtMs = ?,
|
||||
clientIp = ?,
|
||||
clientInfoFromClient = ?,
|
||||
clientInfoFromRequest = ?,
|
||||
userLanguage = ?
|
||||
WHERE sessionId = ?
|
||||
last_authirificated_at_ms = ?,
|
||||
client_ip = ?,
|
||||
client_info_from_client = ?,
|
||||
client_info_from_request = ?,
|
||||
user_language = ?
|
||||
WHERE session_id = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
@@ -231,7 +231,7 @@ public final class ActiveSessionsDAO {
|
||||
|
||||
/** Удалить по sessionId с внешним соединением. Соединение НЕ закрывает. */
|
||||
public void deleteBySessionId(Connection c, String sessionId) throws SQLException {
|
||||
String sql = "DELETE FROM active_sessions WHERE sessionId = ?";
|
||||
String sql = "DELETE FROM active_sessions WHERE session_id = ?";
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
ps.setString(1, sessionId);
|
||||
@@ -249,19 +249,19 @@ public final class ActiveSessionsDAO {
|
||||
// -------------------- MAPPER --------------------
|
||||
|
||||
private ActiveSessionEntry mapRow(ResultSet rs) throws SQLException {
|
||||
String sessionId = rs.getString("sessionId");
|
||||
String sessionId = rs.getString("session_id");
|
||||
String login = rs.getString("login");
|
||||
String sessionPwd = rs.getString("sessionPwd");
|
||||
String storagePwd = rs.getString("storagePwd");
|
||||
long sessionCreatedAtMs = rs.getLong("sessionCreatedAtMs");
|
||||
long lastAuthirificatedAtMs = rs.getLong("lastAuthirificatedAtMs");
|
||||
String pushEndpoint = rs.getString("pushEndpoint");
|
||||
String pushP256dhKey = rs.getString("pushP256dhKey");
|
||||
String pushAuthKey = rs.getString("pushAuthKey");
|
||||
String clientIp = rs.getString("clientIp");
|
||||
String clientInfoFromClient = rs.getString("clientInfoFromClient");
|
||||
String clientInfoFromRequest = rs.getString("clientInfoFromRequest");
|
||||
String userLanguage = rs.getString("userLanguage");
|
||||
String sessionPwd = rs.getString("session_pwd");
|
||||
String storagePwd = rs.getString("storage_pwd");
|
||||
long sessionCreatedAtMs = rs.getLong("session_created_at_ms");
|
||||
long lastAuthirificatedAtMs = rs.getLong("last_authirificated_at_ms");
|
||||
String pushEndpoint = rs.getString("push_endpoint");
|
||||
String pushP256dhKey = rs.getString("push_p256dh_key");
|
||||
String pushAuthKey = rs.getString("push_auth_key");
|
||||
String clientIp = rs.getString("client_ip");
|
||||
String clientInfoFromClient = rs.getString("client_info_from_client");
|
||||
String clientInfoFromRequest = rs.getString("client_info_from_request");
|
||||
String userLanguage = rs.getString("user_language");
|
||||
|
||||
return new ActiveSessionEntry(
|
||||
sessionId,
|
||||
|
||||
@@ -32,9 +32,9 @@ public final class BlockchainStateDAO {
|
||||
public BlockchainStateEntry getByBlockchainName(Connection c, String blockchainName) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
blockchainName,
|
||||
blockchain_name,
|
||||
login,
|
||||
blockchainKey,
|
||||
blockchain_key,
|
||||
size_limit,
|
||||
file_size_bytes,
|
||||
last_global_number,
|
||||
@@ -49,7 +49,7 @@ public final class BlockchainStateDAO {
|
||||
line6_last_number, line6_last_hash,
|
||||
line7_last_number, line7_last_hash
|
||||
FROM blockchain_state
|
||||
WHERE blockchainName = ?
|
||||
WHERE blockchain_name = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
@@ -79,9 +79,9 @@ public final class BlockchainStateDAO {
|
||||
|
||||
String sql = """
|
||||
INSERT INTO blockchain_state (
|
||||
blockchainName,
|
||||
blockchain_name,
|
||||
login,
|
||||
blockchainKey,
|
||||
blockchain_key,
|
||||
size_limit,
|
||||
file_size_bytes,
|
||||
last_global_number,
|
||||
@@ -106,10 +106,10 @@ public final class BlockchainStateDAO {
|
||||
?,?,
|
||||
?,?
|
||||
)
|
||||
ON CONFLICT(blockchainName)
|
||||
ON CONFLICT(blockchain_name)
|
||||
DO UPDATE SET
|
||||
login = excluded.login,
|
||||
blockchainKey = excluded.blockchainKey,
|
||||
blockchain_key = excluded.blockchain_key,
|
||||
size_limit = excluded.size_limit,
|
||||
file_size_bytes = excluded.file_size_bytes,
|
||||
last_global_number = excluded.last_global_number,
|
||||
@@ -158,12 +158,6 @@ public final class BlockchainStateDAO {
|
||||
|
||||
/**
|
||||
* Атомарно увеличить file_size_bytes на deltaBytes, но только если НЕ превысим size_limit.
|
||||
*
|
||||
* Возвращает:
|
||||
* - true если обновили (лимит не превышен)
|
||||
* - false если лимит превышается или blockchainName не найден
|
||||
*
|
||||
* ВАЖНО: это именно тот механизм, который надо дергать при добавлении блока.
|
||||
*/
|
||||
public boolean tryIncreaseFileSizeWithinLimit(Connection c, String blockchainName, long deltaBytes, long nowMs) throws SQLException {
|
||||
String sql = """
|
||||
@@ -172,7 +166,7 @@ public final class BlockchainStateDAO {
|
||||
file_size_bytes = file_size_bytes + ?,
|
||||
updated_at_ms = ?
|
||||
WHERE
|
||||
blockchainName = ?
|
||||
blockchain_name = ?
|
||||
AND (file_size_bytes + ?) <= size_limit
|
||||
""";
|
||||
|
||||
@@ -202,11 +196,10 @@ public final class BlockchainStateDAO {
|
||||
private BlockchainStateEntry mapRow(ResultSet rs) throws SQLException {
|
||||
BlockchainStateEntry e = new BlockchainStateEntry();
|
||||
|
||||
e.setBlockchainName(rs.getString("blockchainName"));
|
||||
e.setBlockchainName(rs.getString("blockchain_name"));
|
||||
e.setLogin(rs.getString("login"));
|
||||
e.setBlockchainKey(rs.getString("blockchainKey"));
|
||||
e.setBlockchainKey(rs.getString("blockchain_key"));
|
||||
|
||||
// size_limit теперь long
|
||||
e.setSizeLimit(rs.getLong("size_limit"));
|
||||
e.setFileSizeBytes(rs.getLong("file_size_bytes"));
|
||||
|
||||
|
||||
@@ -38,19 +38,19 @@ public final class BlocksDAO {
|
||||
String sql = """
|
||||
INSERT INTO blocks (
|
||||
login,
|
||||
bchName,
|
||||
blockGlobalNumber,
|
||||
blockGlobalPreHashe,
|
||||
blockLineIndex,
|
||||
blockLineNumber,
|
||||
blockLinePreHashe,
|
||||
msgType,
|
||||
msgSubType,
|
||||
blockByte,
|
||||
bch_name,
|
||||
block_global_number,
|
||||
block_global_pre_hashe,
|
||||
block_line_index,
|
||||
block_line_number,
|
||||
block_line_pre_hashe,
|
||||
msg_type,
|
||||
msg_sub_type,
|
||||
block_byte,
|
||||
to_login,
|
||||
toBchName,
|
||||
toBlockGlobalNumber,
|
||||
toBlockHashe
|
||||
to_bch_name,
|
||||
to_block_global_number,
|
||||
to_block_hashe
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
@@ -69,16 +69,11 @@ public final class BlocksDAO {
|
||||
|
||||
// -------------------- UPSERT (UPDATE -> INSERT) --------------------
|
||||
|
||||
/**
|
||||
* Сохранить (условный upsert) с внешним соединением. Соединение НЕ закрывает.
|
||||
* Без PK/UNIQUE делаем: UPDATE по "ключевым" полям -> если 0 строк, то INSERT.
|
||||
*/
|
||||
public void upsert(Connection c, BlockEntry e) throws SQLException {
|
||||
int updated = update(c, e);
|
||||
if (updated == 0) insert(c, e);
|
||||
}
|
||||
|
||||
/** Сохранить (upsert) без внешнего соединения. Сам открывает/закрывает. */
|
||||
public void upsert(BlockEntry e) throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
upsert(c, e);
|
||||
@@ -87,7 +82,6 @@ public final class BlocksDAO {
|
||||
|
||||
// -------------------- SELECT --------------------
|
||||
|
||||
/** Получить блок по "PK-подобному" набору полей с внешним соединением. Соединение НЕ закрывает. */
|
||||
public BlockEntry getByPk(Connection c,
|
||||
String login,
|
||||
String bchName,
|
||||
@@ -98,26 +92,26 @@ public final class BlocksDAO {
|
||||
String sql = """
|
||||
SELECT
|
||||
login,
|
||||
bchName,
|
||||
blockGlobalNumber,
|
||||
blockGlobalPreHashe,
|
||||
blockLineIndex,
|
||||
blockLineNumber,
|
||||
blockLinePreHashe,
|
||||
msgType,
|
||||
msgSubType,
|
||||
blockByte,
|
||||
bch_name,
|
||||
block_global_number,
|
||||
block_global_pre_hashe,
|
||||
block_line_index,
|
||||
block_line_number,
|
||||
block_line_pre_hashe,
|
||||
msg_type,
|
||||
msg_sub_type,
|
||||
block_byte,
|
||||
to_login,
|
||||
toBchName,
|
||||
toBlockGlobalNumber,
|
||||
toBlockHashe
|
||||
to_bch_name,
|
||||
to_block_global_number,
|
||||
to_block_hashe
|
||||
FROM blocks
|
||||
WHERE
|
||||
login = ?
|
||||
AND bchName = ?
|
||||
AND blockGlobalNumber = ?
|
||||
AND blockLineIndex = ?
|
||||
AND blockLineNumber = ?
|
||||
AND bch_name = ?
|
||||
AND block_global_number = ?
|
||||
AND block_line_index = ?
|
||||
AND block_line_number = ?
|
||||
LIMIT 1
|
||||
""";
|
||||
|
||||
@@ -135,7 +129,6 @@ public final class BlocksDAO {
|
||||
}
|
||||
}
|
||||
|
||||
/** Получить блок по "PK-подобному" набору полей без внешнего соединения. Сам открывает/закрывает. */
|
||||
public BlockEntry getByPk(String login,
|
||||
String bchName,
|
||||
int blockGlobalNumber,
|
||||
@@ -148,29 +141,25 @@ public final class BlocksDAO {
|
||||
|
||||
// -------------------- UPDATE --------------------
|
||||
|
||||
/**
|
||||
* Обновить (строго UPDATE) по "PK-подобному" набору полей с внешним соединением. Соединение НЕ закрывает.
|
||||
* Может обновить >1 строк, если в таблице появились дубликаты.
|
||||
*/
|
||||
public int update(Connection c, BlockEntry e) throws SQLException {
|
||||
String sql = """
|
||||
UPDATE blocks
|
||||
SET
|
||||
blockGlobalPreHashe = ?,
|
||||
blockLinePreHashe = ?,
|
||||
msgType = ?,
|
||||
msgSubType = ?,
|
||||
blockByte = ?,
|
||||
to_login = ?,
|
||||
toBchName = ?,
|
||||
toBlockGlobalNumber = ?,
|
||||
toBlockHashe = ?
|
||||
block_global_pre_hashe = ?,
|
||||
block_line_pre_hashe = ?,
|
||||
msg_type = ?,
|
||||
msg_sub_type = ?,
|
||||
block_byte = ?,
|
||||
to_login = ?,
|
||||
to_bch_name = ?,
|
||||
to_block_global_number = ?,
|
||||
to_block_hashe = ?
|
||||
WHERE
|
||||
login = ?
|
||||
AND bchName = ?
|
||||
AND blockGlobalNumber = ?
|
||||
AND blockLineIndex = ?
|
||||
AND blockLineNumber = ?
|
||||
AND bch_name = ?
|
||||
AND block_global_number = ?
|
||||
AND block_line_index = ?
|
||||
AND block_line_number = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
@@ -207,7 +196,6 @@ public final class BlocksDAO {
|
||||
}
|
||||
}
|
||||
|
||||
/** Обновить без внешнего соединения. Сам открывает/закрывает. */
|
||||
public int update(BlockEntry e) throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
return update(c, e);
|
||||
@@ -216,10 +204,6 @@ public final class BlocksDAO {
|
||||
|
||||
// -------------------- DELETE --------------------
|
||||
|
||||
/**
|
||||
* Удалить по "PK-подобному" набору полей с внешним соединением. Соединение НЕ закрывает.
|
||||
* Может удалить >1 строк, если есть дубликаты.
|
||||
*/
|
||||
public int deleteByPk(Connection c,
|
||||
String login,
|
||||
String bchName,
|
||||
@@ -231,10 +215,10 @@ public final class BlocksDAO {
|
||||
DELETE FROM blocks
|
||||
WHERE
|
||||
login = ?
|
||||
AND bchName = ?
|
||||
AND blockGlobalNumber = ?
|
||||
AND blockLineIndex = ?
|
||||
AND blockLineNumber = ?
|
||||
AND bch_name = ?
|
||||
AND block_global_number = ?
|
||||
AND block_line_index = ?
|
||||
AND block_line_number = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
@@ -247,7 +231,6 @@ public final class BlocksDAO {
|
||||
}
|
||||
}
|
||||
|
||||
/** Удалить по "PK-подобному" набору полей без внешнего соединения. Сам открывает/закрывает. */
|
||||
public int deleteByPk(String login,
|
||||
String bchName,
|
||||
int blockGlobalNumber,
|
||||
@@ -260,7 +243,6 @@ public final class BlocksDAO {
|
||||
|
||||
// -------------------- INTERNAL --------------------
|
||||
|
||||
/** Единая привязка параметров под INSERT — чтобы не разъезжалось. */
|
||||
private static void bindAll(PreparedStatement ps, BlockEntry e) throws SQLException {
|
||||
int i = 1;
|
||||
|
||||
@@ -297,29 +279,29 @@ public final class BlocksDAO {
|
||||
BlockEntry e = new BlockEntry();
|
||||
|
||||
e.setLogin(rs.getString("login"));
|
||||
e.setBchName(rs.getString("bchName"));
|
||||
e.setBlockGlobalNumber(rs.getInt("blockGlobalNumber"));
|
||||
e.setBlockGlobalPreHashe(rs.getString("blockGlobalPreHashe"));
|
||||
e.setBchName(rs.getString("bch_name"));
|
||||
e.setBlockGlobalNumber(rs.getInt("block_global_number"));
|
||||
e.setBlockGlobalPreHashe(rs.getString("block_global_pre_hashe"));
|
||||
|
||||
e.setBlockLineIndex(rs.getInt("blockLineIndex"));
|
||||
e.setBlockLineNumber(rs.getInt("blockLineNumber"));
|
||||
e.setBlockLinePreHashe(rs.getString("blockLinePreHashe"));
|
||||
e.setBlockLineIndex(rs.getInt("block_line_index"));
|
||||
e.setBlockLineNumber(rs.getInt("block_line_number"));
|
||||
e.setBlockLinePreHashe(rs.getString("block_line_pre_hashe"));
|
||||
|
||||
e.setMsgType(rs.getInt("msgType"));
|
||||
e.setMsgSubType(rs.getInt("msgSubType"));
|
||||
e.setMsgType(rs.getInt("msg_type"));
|
||||
e.setMsgSubType(rs.getInt("msg_sub_type"));
|
||||
|
||||
e.setBlockByte(rs.getBytes("blockByte"));
|
||||
e.setBlockByte(rs.getBytes("block_byte"));
|
||||
|
||||
e.setToLogin(rs.getString("to_login"));
|
||||
|
||||
String toBchName = rs.getString("toBchName");
|
||||
String toBchName = rs.getString("to_bch_name");
|
||||
if (rs.wasNull()) toBchName = null;
|
||||
e.setToBchName(toBchName);
|
||||
|
||||
Integer toBlockGlobalNumber = (Integer) rs.getObject("toBlockGlobalNumber");
|
||||
Integer toBlockGlobalNumber = (Integer) rs.getObject("to_block_global_number");
|
||||
e.setToBlockGlobalNumber(toBlockGlobalNumber);
|
||||
|
||||
String toBlockHashe = rs.getString("toBlockHashe");
|
||||
String toBlockHashe = rs.getString("to_block_hashe");
|
||||
if (rs.wasNull()) toBlockHashe = null;
|
||||
e.setToBlockHashe(toBlockHashe);
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ import java.sql.*;
|
||||
/**
|
||||
* DAO для таблицы ip_geo_cache.
|
||||
*
|
||||
* * Таблица:
|
||||
* * - ip TEXT PRIMARY KEY
|
||||
* * - geo TEXT
|
||||
* * - updated_at_ms INTEGER NOT NULL
|
||||
* Таблица:
|
||||
* - ip TEXT PRIMARY KEY
|
||||
* - geo TEXT
|
||||
* - updated_at_ms INTEGER NOT NULL
|
||||
*
|
||||
* Правило:
|
||||
* - методы с Connection НЕ закрывают соединение
|
||||
|
||||
@@ -14,18 +14,8 @@ import java.util.List;
|
||||
*
|
||||
* Колонки:
|
||||
* - login TEXT PRIMARY KEY
|
||||
* Уникальный логин пользователя (case-insensitive используется на уровне запросов).
|
||||
*
|
||||
* - deviceKey TEXT NOT NULL
|
||||
* Публичный ключ устройства пользователя.
|
||||
* Хранится в Base64(32 bytes) или HEX(64 chars).
|
||||
*
|
||||
* - solanaKey TEXT NULLABLE
|
||||
* Публичный ключ Solana-аккаунта пользователя (если есть).
|
||||
*
|
||||
* Назначение таблицы:
|
||||
* - локальное сопоставление login → deviceKey / solanaKey
|
||||
* - используется для аутентификации, валидации подписей и связки с блокчейном
|
||||
* - device_key TEXT NOT NULL
|
||||
* - solana_key TEXT NULLABLE
|
||||
*
|
||||
* Правило работы с соединениями:
|
||||
* - методы с Connection НЕ закрывают соединение
|
||||
@@ -52,7 +42,7 @@ public final class SolanaUsersDAO {
|
||||
/** Вставка с внешним соединением. Соединение НЕ закрывает. */
|
||||
public void insert(Connection c, SolanaUserEntry user) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO solana_users (login, deviceKey, solanaKey)
|
||||
INSERT INTO solana_users (login, device_key, solana_key)
|
||||
VALUES (?, ?, ?)
|
||||
""";
|
||||
|
||||
@@ -102,7 +92,7 @@ public final class SolanaUsersDAO {
|
||||
/** Получить по login (case-insensitive) с внешним соединением. Соединение НЕ закрывает. */
|
||||
public SolanaUserEntry getByLogin(Connection c, String login) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, deviceKey, solanaKey
|
||||
SELECT login, device_key, solana_key
|
||||
FROM solana_users
|
||||
WHERE LOWER(login) = LOWER(?)
|
||||
""";
|
||||
@@ -126,7 +116,7 @@ public final class SolanaUsersDAO {
|
||||
/** Поиск по префиксу с внешним соединением. Соединение НЕ закрывает. */
|
||||
public List<SolanaUserEntry> searchByLoginPrefix(Connection c, String prefix) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, deviceKey, solanaKey
|
||||
SELECT login, device_key, solana_key
|
||||
FROM solana_users
|
||||
WHERE LOWER(login) LIKE ?
|
||||
ORDER BY login
|
||||
@@ -157,10 +147,10 @@ public final class SolanaUsersDAO {
|
||||
private SolanaUserEntry mapRow(ResultSet rs) throws SQLException {
|
||||
SolanaUserEntry e = new SolanaUserEntry(
|
||||
rs.getString("login"),
|
||||
rs.getString("deviceKey")
|
||||
rs.getString("device_key")
|
||||
);
|
||||
|
||||
String solanaKey = rs.getString("solanaKey");
|
||||
String solanaKey = rs.getString("solana_key");
|
||||
if (rs.wasNull()) solanaKey = null;
|
||||
e.setSolanaKey(solanaKey);
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import java.sql.*;
|
||||
|
||||
/**
|
||||
* UserCreateDAO — атомарное добавление пользователя:
|
||||
* - solana_users (login, deviceKey)
|
||||
* - blockchain_state (blockchainName, login, blockchainKey, size_limit, ... last_global_number=-1 ...)
|
||||
* - solana_users (login, device_key)
|
||||
* - blockchain_state (blockchain_name, login, blockchain_key, size_limit, ... last_global_number=-1 ...)
|
||||
*
|
||||
* ВАЖНО:
|
||||
* - только INSERT
|
||||
@@ -86,8 +86,6 @@ public final class UserCreateDAO {
|
||||
} catch (SQLException e) {
|
||||
c.rollback();
|
||||
|
||||
// SQLITE_CONSTRAINT -> "уже существует"
|
||||
// Мы не делаем UPDATE, только insert.
|
||||
String msg = e.getMessage() == null ? "" : e.getMessage().toLowerCase();
|
||||
if (msg.contains("constraint")) {
|
||||
return false;
|
||||
|
||||
@@ -17,11 +17,6 @@ import java.util.List;
|
||||
* ЛОГИКА time_ms:
|
||||
* - БД принимает запись только если она "новее" (time_ms строго больше текущего).
|
||||
* - Реализовано атомарно одним SQL: UPSERT + WHERE users_params.time_ms < excluded.time_ms
|
||||
*
|
||||
* Возврат результата:
|
||||
* - upsertIfNewer(...) возвращает количество изменённых строк:
|
||||
* 1 = вставили/обновили
|
||||
* 0 = проигнорировали (запись уже новее или равная)
|
||||
*/
|
||||
public final class UserParamsDAO {
|
||||
|
||||
@@ -41,11 +36,6 @@ public final class UserParamsDAO {
|
||||
|
||||
// -------------------- UPSERT (IF NEWER) --------------------
|
||||
|
||||
/**
|
||||
* Атомарный UPSERT "только если новее".
|
||||
*
|
||||
* @return 1 если вставили/обновили; 0 если запись не тронули (existing.time_ms >= incoming.time_ms).
|
||||
*/
|
||||
public int upsertIfNewer(Connection c, UserParamEntry e) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO users_params (
|
||||
@@ -77,11 +67,10 @@ public final class UserParamsDAO {
|
||||
if (e.getSignature() != null) ps.setString(6, e.getSignature());
|
||||
else ps.setNull(6, Types.VARCHAR);
|
||||
|
||||
return ps.executeUpdate(); // 1 или 0
|
||||
return ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/** То же самое, но сам открывает/закрывает соединение. */
|
||||
public int upsertIfNewer(UserParamEntry e) throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
return upsertIfNewer(c, e);
|
||||
@@ -90,7 +79,6 @@ public final class UserParamsDAO {
|
||||
|
||||
// -------------------- SELECT --------------------
|
||||
|
||||
/** Получить параметр по (login,param) с внешним соединением. Соединение НЕ закрывает. */
|
||||
public UserParamEntry getByLoginAndParam(Connection c, String login, String param) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
@@ -116,14 +104,12 @@ public final class UserParamsDAO {
|
||||
}
|
||||
}
|
||||
|
||||
/** Получить параметр по (login,param) без внешнего соединения. Сам открывает/закрывает. */
|
||||
public UserParamEntry getByLoginAndParam(String login, String param) throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
return getByLoginAndParam(c, login, param);
|
||||
}
|
||||
}
|
||||
|
||||
/** Получить все параметры пользователя с внешним соединением. */
|
||||
public List<UserParamEntry> getByLogin(Connection c, String login) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
@@ -148,7 +134,6 @@ public final class UserParamsDAO {
|
||||
return list;
|
||||
}
|
||||
|
||||
/** Получить все параметры пользователя без внешнего соединения. */
|
||||
public List<UserParamEntry> getByLogin(String login) throws SQLException {
|
||||
try (Connection c = db.getConnection()) {
|
||||
return getByLogin(c, login);
|
||||
|
||||
@@ -2,27 +2,23 @@ package shine.db.entities;
|
||||
|
||||
/**
|
||||
* Модель активной сессии (таблица active_sessions).
|
||||
*
|
||||
* Теперь вместо loginId:
|
||||
* - login TEXT NOT NULL (FK -> solana_users(login))
|
||||
*/
|
||||
public class ActiveSessionEntry {
|
||||
|
||||
private String sessionId; // TEXT base64(32 bytes)
|
||||
private String login; // TEXT NOT NULL
|
||||
private String sessionPwd; // TEXT
|
||||
private String storagePwd; // TEXT
|
||||
private long sessionCreatedAtMs; // INTEGER
|
||||
private long lastAuthirificatedAtMs; // INTEGER
|
||||
private String pushEndpoint; // TEXT (nullable)
|
||||
private String pushP256dhKey; // TEXT (nullable)
|
||||
private String pushAuthKey; // TEXT (nullable)
|
||||
private String sessionId;
|
||||
private String login;
|
||||
private String sessionPwd;
|
||||
private String storagePwd;
|
||||
private long sessionCreatedAtMs;
|
||||
private long lastAuthirificatedAtMs;
|
||||
private String pushEndpoint;
|
||||
private String pushP256dhKey;
|
||||
private String pushAuthKey;
|
||||
|
||||
// Новые поля
|
||||
private String clientIp; // IP клиента при auth/refresh
|
||||
private String clientInfoFromClient; // строка от клиента (PWA)
|
||||
private String clientInfoFromRequest; // строка, собранная на сервере
|
||||
private String userLanguage; // prefer-language (например, "ru-RU")
|
||||
private String clientIp;
|
||||
private String clientInfoFromClient;
|
||||
private String clientInfoFromRequest;
|
||||
private String userLanguage;
|
||||
|
||||
public ActiveSessionEntry() {
|
||||
}
|
||||
|
||||
@@ -2,41 +2,28 @@ package shine.db.entities;
|
||||
|
||||
/**
|
||||
* Запись блока (таблица blocks).
|
||||
*
|
||||
* Теперь:
|
||||
* - login TEXT NOT NULL
|
||||
* - bchName TEXT NOT NULL (идёт сразу после login)
|
||||
* - to_login TEXT nullable
|
||||
* - toBchName TEXT nullable
|
||||
* - toBlockGlobalNumber INTEGER nullable
|
||||
* - toBlockHashe TEXT nullable
|
||||
*
|
||||
* ДОБАВЛЕНО:
|
||||
* - msgSubType INTEGER (uint16 по смыслу, храним как int)
|
||||
*
|
||||
* PRIMARY KEY пока убран вообще.
|
||||
*/
|
||||
public class BlockEntry {
|
||||
|
||||
private String login; // TEXT
|
||||
private String bchName; // TEXT
|
||||
private String login;
|
||||
private String bchName;
|
||||
|
||||
private int blockGlobalNumber; // int32
|
||||
private String blockGlobalPreHashe; // TEXT
|
||||
private int blockGlobalNumber;
|
||||
private String blockGlobalPreHashe;
|
||||
|
||||
private int blockLineIndex; // int16 (храним как int)
|
||||
private int blockLineNumber; // int32
|
||||
private String blockLinePreHashe; // TEXT
|
||||
private int blockLineIndex;
|
||||
private int blockLineNumber;
|
||||
private String blockLinePreHashe;
|
||||
|
||||
private int msgType; // int16 (храним как int)
|
||||
private int msgSubType; // int16 (храним как int)
|
||||
private int msgType;
|
||||
private int msgSubType;
|
||||
|
||||
private byte[] blockByte; // BLOB
|
||||
private byte[] blockByte;
|
||||
|
||||
private String toLogin; // TEXT nullable
|
||||
private String toBchName; // TEXT nullable
|
||||
private Integer toBlockGlobalNumber; // INTEGER nullable
|
||||
private String toBlockHashe; // TEXT nullable
|
||||
private String toLogin;
|
||||
private String toBchName;
|
||||
private Integer toBlockGlobalNumber;
|
||||
private String toBlockHashe;
|
||||
|
||||
public BlockEntry() {}
|
||||
|
||||
|
||||
@@ -5,29 +5,22 @@ import java.util.Base64;
|
||||
|
||||
/**
|
||||
* Агрегатная сущность текущего состояния блокчейна.
|
||||
* 1 строка = 1 blockchainName, плюс состояние линий 0..7.
|
||||
* 1 строка = 1 blockchain_name, плюс состояние линий 0..7.
|
||||
*/
|
||||
public final class BlockchainStateEntry {
|
||||
|
||||
private String blockchainName;
|
||||
|
||||
private String login;
|
||||
|
||||
/** Ключ блокчейна (pubkey), которым подписываются блоки. Base64(32 bytes). */
|
||||
private String blockchainKey;
|
||||
|
||||
/** Лимит (теперь long). */
|
||||
private long sizeLimit;
|
||||
|
||||
/** Размер файла блокчейна в байтах (то, что будем сверять/чинить при старте). */
|
||||
private long fileSizeBytes;
|
||||
|
||||
private int lastGlobalNumber;
|
||||
private String lastGlobalHash; // HEX(64) либо пустая строка для "нулевого"
|
||||
private String lastGlobalHash;
|
||||
|
||||
/** line 0..7 */
|
||||
private final int[] lastLineNumbers = new int[8];
|
||||
/** line 0..7 */
|
||||
private final String[] lastLineHashes = new String[8];
|
||||
|
||||
private long updatedAtMs;
|
||||
@@ -78,7 +71,6 @@ public final class BlockchainStateEntry {
|
||||
public String getBlockchainKey() { return blockchainKey; }
|
||||
public void setBlockchainKey(String blockchainKey) { this.blockchainKey = blockchainKey; }
|
||||
|
||||
/** blockchainKey в байтах (32) или null, если битый. */
|
||||
public byte[] getBlockchainKeyBytes() {
|
||||
if (blockchainKey == null) return null;
|
||||
String s = blockchainKey.trim();
|
||||
@@ -103,7 +95,6 @@ public final class BlockchainStateEntry {
|
||||
public String getLastGlobalHash() { return lastGlobalHash; }
|
||||
public void setLastGlobalHash(String lastGlobalHash) { this.lastGlobalHash = lastGlobalHash == null ? "" : lastGlobalHash; }
|
||||
|
||||
/** line in [0..7] */
|
||||
public int getLastLineNumber(int line) {
|
||||
checkLine(line);
|
||||
return lastLineNumbers[line];
|
||||
@@ -113,7 +104,6 @@ public final class BlockchainStateEntry {
|
||||
lastLineNumbers[line] = value;
|
||||
}
|
||||
|
||||
/** line in [0..7] */
|
||||
public String getLastLineHash(int line) {
|
||||
checkLine(line);
|
||||
return lastLineHashes[line];
|
||||
|
||||
@@ -2,11 +2,6 @@ package shine.db.entities;
|
||||
|
||||
/**
|
||||
* Запись в таблице ip_geo_cache.
|
||||
*
|
||||
* Храним:
|
||||
* - ip — строка IP-адреса (PRIMARY KEY)
|
||||
* - geo — строка "Country, City" или любое текстовое описание
|
||||
* - updatedAtMs — время последнего обновления (Unix time в мс)
|
||||
*/
|
||||
public class IpGeoCacheEntry {
|
||||
|
||||
|
||||
@@ -8,35 +8,15 @@ import java.util.Base64;
|
||||
* Таблица: solana_users
|
||||
*
|
||||
* Поля:
|
||||
* - login — PRIMARY KEY (TEXT)
|
||||
* Уникальный логин пользователя.
|
||||
*
|
||||
* - deviceKey — TEXT NOT NULL
|
||||
* Публичный ключ устройства.
|
||||
* Поддерживаемые форматы:
|
||||
* • Base64 (32 байта)
|
||||
* • HEX (64 hex-символа)
|
||||
*
|
||||
* - solanaKey — TEXT NULLABLE
|
||||
* Публичный ключ Solana-аккаунта пользователя (если используется).
|
||||
*
|
||||
* Назначение:
|
||||
* - хранение минимальной локальной информации о пользователе
|
||||
* - используется для:
|
||||
* • проверки подписи запросов
|
||||
* • привязки пользователя к блокчейну
|
||||
* • сопоставления login ↔ ключи
|
||||
*
|
||||
* ВАЖНО:
|
||||
* - deviceKey обязателен всегда
|
||||
* - solanaKey может отсутствовать (null)
|
||||
* - login — PRIMARY KEY (TEXT)
|
||||
* - device_key — TEXT NOT NULL
|
||||
* - solana_key — TEXT NULLABLE
|
||||
*/
|
||||
|
||||
public class SolanaUserEntry {
|
||||
|
||||
private String login; // TEXT PK
|
||||
private String deviceKey; // TEXT NOT NULL (Base64(32 bytes))
|
||||
private String solanaKey; // TEXT
|
||||
private String login;
|
||||
private String deviceKey;
|
||||
private String solanaKey;
|
||||
|
||||
public SolanaUserEntry() {}
|
||||
|
||||
@@ -54,32 +34,22 @@ public class SolanaUserEntry {
|
||||
public String getLogin() { return login; }
|
||||
public void setLogin(String login) { this.login = login; }
|
||||
|
||||
/** Публичный ключ устройства (device key). */
|
||||
public String getDeviceKey() { return deviceKey; }
|
||||
public void setDeviceKey(String deviceKey) { this.deviceKey = deviceKey; }
|
||||
|
||||
public String getSolanaKey() { return solanaKey; }
|
||||
public void setSolanaKey(String solanaKey) { this.solanaKey = solanaKey; }
|
||||
|
||||
/**
|
||||
* Device key в байтах (32 байта) или null, если ключ битый/пустой.
|
||||
*
|
||||
* Поддержка форматов:
|
||||
* - Base64 (предпочтительно)
|
||||
* - HEX (ровно 64 hex-символа, без пробелов)
|
||||
*/
|
||||
public byte[] getDeviceKeyByte() {
|
||||
if (deviceKey == null) return null;
|
||||
String s = deviceKey.trim();
|
||||
if (s.isEmpty()) return null;
|
||||
|
||||
// 1) пробуем Base64
|
||||
try {
|
||||
byte[] b = Base64.getDecoder().decode(s);
|
||||
if (b != null && b.length == 32) return b;
|
||||
} catch (IllegalArgumentException ignore) {}
|
||||
|
||||
// 2) пробуем HEX (64 символа)
|
||||
if (s.length() == 64 && s.matches("^[0-9a-fA-F]+$")) {
|
||||
byte[] out = new byte[32];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
|
||||
@@ -10,12 +10,6 @@ package shine.db.entities;
|
||||
* - value TEXT NOT NULL
|
||||
* - device_key TEXT NULL
|
||||
* - signature TEXT NULL
|
||||
*
|
||||
* UNIQUE(login, param)
|
||||
*
|
||||
* Смысл:
|
||||
* - в таблице всегда хранится "последнее" значение параметра по времени.
|
||||
* - time_ms монотонно растёт для каждого (login,param) — сервер не принимает более старые обновления.
|
||||
*/
|
||||
public class UserParamEntry {
|
||||
|
||||
@@ -24,8 +18,8 @@ public class UserParamEntry {
|
||||
private long timeMs;
|
||||
private String value;
|
||||
|
||||
private String deviceKey; // base64(32) — можно хранить как "каким ключом подписано"
|
||||
private String signature; // base64(64)
|
||||
private String deviceKey;
|
||||
private String signature;
|
||||
|
||||
public UserParamEntry() {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user