Сделал что бы в базу писался msgSubType и поля to (to login, toBlockchainName и т.д.)
This commit is contained in:
AidarKC 2026-01-02 20:15:59 +03:00
parent eef760d776
commit dd49c4de00
8 changed files with 129 additions and 22 deletions

View File

@ -0,0 +1,32 @@
package blockchain.body;
/**
* BodyToFields дополнительный интерфейс для body, которые "ссылаются" на цель (to-поля).
*
* Идея:
* - Не все body имеют "to".
* - Но для индексации и удобства запросов в БД мы хотим единообразно доставать:
* toLogin, toBchName, toBlockGlobalNumber, toBlockHashe
*
* Важно:
* - Все методы могут возвращать null.
* - toLogin может отсутствовать в самом формате body (например, ReactionBody, TextBody reply/repost),
* но в БД мы пишем toLogin "про запас".
* Поэтому writer может:
* - взять toLogin из body (если есть),
* - либо попытаться вычислить из toBchName.
*/
public interface BodyHasTarget {
/** login цели (nullable). */
String toLogin();
/** blockchainName цели (nullable). */
String toBchName();
/** globalNumber цели (nullable). */
Integer toBlockGlobalNumber();
/** hash цели в HEX(64) (nullable). */
String toBlockHashe();
}

View File

@ -42,7 +42,7 @@ import java.util.Objects;
* ЛИНИЯ:
* - строго lineIndex=3 (выделяем отдельную линию под связи).
*/
public final class ConnectionBody implements BodyRecord {
public final class ConnectionBody implements BodyRecord, BodyHasTarget {
public static final short TYPE = 3;
public static final short VER = 1;
@ -279,4 +279,16 @@ public final class ConnectionBody implements BodyRecord {
}
return new String(out);
}
/* ===================================================================== */
/* ====================== BodyToFields контракт ========================= */
/* ===================================================================== */
@Override public String toLogin() { return toLogin; }
@Override public String toBchName() { return toBlockchainName; }
@Override public Integer toBlockGlobalNumber() { return toBlockGlobalNumber; }
@Override public String toBlockHashe() { return toBlockHashHex(); }
}

View File

@ -31,7 +31,7 @@ import java.util.Objects;
* - Здесь мы НЕ проверяем, существует ли цель реакции.
* - Мы проверяем только корректность формата и целостность полей.
*/
public final class ReactionBody implements BodyRecord {
public final class ReactionBody implements BodyRecord, BodyHasTarget {
public static final short TYPE = 2;
public static final short VER = 1;
@ -189,4 +189,17 @@ public final class ReactionBody implements BodyRecord {
}
return new String(out);
}
/* ===================================================================== */
/* ====================== BodyToFields контракт ========================= */
/* ===================================================================== */
/** В самом формате ReactionBody login цели не хранится => null. */
@Override public String toLogin() { return null; }
@Override public String toBchName() { return toBlockchainName; }
@Override public Integer toBlockGlobalNumber() { return toBlockGlobalNumber; }
@Override public String toBlockHashe() { return toBlockHashHex(); }
}

View File

@ -41,7 +41,7 @@ import java.util.Objects;
* - для subType=NEW запрещены поля ссылки и запрещены любые лишние байты в хвосте
* - для subType=REPLY/REPOST хвост обязан быть ровно по формату и без мусора в конце
*/
public final class TextBody implements BodyRecord {
public final class TextBody implements BodyRecord, BodyHasTarget {
public static final short TYPE = 1;
public static final short VER = 1;
@ -219,8 +219,6 @@ public final class TextBody implements BodyRecord {
@Override public short type() { return TYPE; }
@Override public short version() { return VER; }
/** ✅ ВАЖНО: теперь BodyRecord требует subType() */
@Override public short subType() { return subType; }
@Override
@ -363,4 +361,26 @@ public final class TextBody implements BodyRecord {
}
return new String(out);
}
/* ===================================================================== */
/* ====================== BodyToFields контракт ========================= */
/* ===================================================================== */
/** В формате TextBody login цели не хранится => null. */
@Override public String toLogin() { return null; }
@Override
public String toBchName() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockchainName : null;
}
@Override
public Integer toBlockGlobalNumber() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockGlobalNumber : null;
}
@Override
public String toBlockHashe() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockHashHex() : null;
}
}

View File

@ -21,6 +21,10 @@ import java.sql.Statement;
* - ip_geo_cache
* - blockchain_state (MVP)
* - blocks (login TEXT, bchName TEXT, PK убран)
*
* ОБНОВЛЕНО:
* - blocks: добавлено поле msgSubType (сразу после msgType)
* - blocks: поля to* остаются nullable
*/
public class DatabaseInitializer {
@ -195,7 +199,7 @@ public class DatabaseInitializer {
ON blockchain_state (updated_at_ms);
""");
// 6. blocks PK удалён полностью, to* теперь nullable
// 6. blocks PK удалён полностью, to* теперь nullable, добавлен msgSubType
st.executeUpdate("""
CREATE TABLE IF NOT EXISTS blocks (
login TEXT NOT NULL,
@ -208,6 +212,7 @@ public class DatabaseInitializer {
blockLinePreHashe TEXT NOT NULL,
msgType INTEGER NOT NULL,
msgSubType INTEGER NOT NULL,
blockByte BLOB,

View File

@ -45,12 +45,13 @@ public final class BlocksDAO {
blockLineNumber,
blockLinePreHashe,
msgType,
msgSubType,
blockByte,
to_login,
toBchName,
toBlockGlobalNumber,
toBlockHashe
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""";
try (PreparedStatement ps = c.prepareStatement(sql)) {
@ -104,6 +105,7 @@ public final class BlocksDAO {
blockLineNumber,
blockLinePreHashe,
msgType,
msgSubType,
blockByte,
to_login,
toBchName,
@ -157,6 +159,7 @@ public final class BlocksDAO {
blockGlobalPreHashe = ?,
blockLinePreHashe = ?,
msgType = ?,
msgSubType = ?,
blockByte = ?,
to_login = ?,
toBchName = ?,
@ -176,6 +179,7 @@ public final class BlocksDAO {
ps.setString(i++, nn(e.getBlockGlobalPreHashe()));
ps.setString(i++, nn(e.getBlockLinePreHashe()));
ps.setInt(i++, e.getMsgType());
ps.setInt(i++, e.getMsgSubType());
byte[] bytes = e.getBlockByte();
if (bytes != null) ps.setBytes(i++, bytes);
@ -270,6 +274,7 @@ public final class BlocksDAO {
ps.setString(i++, nn(e.getBlockLinePreHashe()));
ps.setInt(i++, e.getMsgType());
ps.setInt(i++, e.getMsgSubType());
byte[] bytes = e.getBlockByte();
if (bytes != null) ps.setBytes(i++, bytes);
@ -301,6 +306,7 @@ public final class BlocksDAO {
e.setBlockLinePreHashe(rs.getString("blockLinePreHashe"));
e.setMsgType(rs.getInt("msgType"));
e.setMsgSubType(rs.getInt("msgSubType"));
e.setBlockByte(rs.getBytes("blockByte"));

View File

@ -11,6 +11,9 @@ package shine.db.entities;
* - toBlockGlobalNumber INTEGER nullable
* - toBlockHashe TEXT nullable
*
* ДОБАВЛЕНО:
* - msgSubType INTEGER (uint16 по смыслу, храним как int)
*
* PRIMARY KEY пока убран вообще.
*/
public class BlockEntry {
@ -26,6 +29,7 @@ public class BlockEntry {
private String blockLinePreHashe; // TEXT
private int msgType; // int16 (храним как int)
private int msgSubType; // int16 (храним как int)
private byte[] blockByte; // BLOB
@ -44,6 +48,7 @@ public class BlockEntry {
int blockLineNumber,
String blockLinePreHashe,
int msgType,
int msgSubType,
byte[] blockByte,
String toLogin,
String toBchName,
@ -57,6 +62,7 @@ public class BlockEntry {
this.blockLineNumber = blockLineNumber;
this.blockLinePreHashe = blockLinePreHashe;
this.msgType = msgType;
this.msgSubType = msgSubType;
this.blockByte = blockByte;
this.toLogin = toLogin;
this.toBchName = toBchName;
@ -88,6 +94,9 @@ public class BlockEntry {
public int getMsgType() { return msgType; }
public void setMsgType(int msgType) { this.msgType = msgType; }
public int getMsgSubType() { return msgSubType; }
public void setMsgSubType(int msgSubType) { this.msgSubType = msgSubType; }
public byte[] getBlockByte() { return blockByte; }
public void setBlockByte(byte[] blockByte) { this.blockByte = blockByte; }

View File

@ -1,7 +1,7 @@
package server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils;
import blockchain.BchBlockEntry;
import blockchain.body.ReactionBody;
import blockchain.body.BodyHasTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import shine.db.SqliteDbController;
@ -281,7 +281,12 @@ public final class BlockchainWriter {
* Важно:
* - blockLinePreHashe = prevLineHashHex (а НЕ prevGlobalHashHex)
* - msgType = body.type()
* - Для ReactionBody заполняем toBchName/toBlockGlobalNumber/toBlockHashe (+ to_login если можем).
* - msgSubType = body.subType()
* - to* поля берём через BodyToFields (если body его поддерживает)
*
* Про toLogin:
* - если body сам даёт toLogin пишем его
* - иначе, если есть toBchName пробуем вычислить login из имени блокчейна (про запас)
*/
private void insertBlockRow(
Connection c,
@ -311,6 +316,7 @@ public final class BlockchainWriter {
e.setBlockLinePreHashe(linePre);
e.setMsgType(block.body.type());
e.setMsgSubType(block.body.subType());
e.setBlockByte(block.toBytes());
@ -320,18 +326,22 @@ public final class BlockchainWriter {
e.setToBlockGlobalNumber(null);
e.setToBlockHashe(null);
// ReactionBody -> target fields
if (block.body instanceof ReactionBody rb) {
e.setToBchName(rb.toBlockchainName);
e.setToBlockGlobalNumber(rb.toBlockGlobalNumber);
e.setToBlockHashe(rb.toBlockHashHex());
// Универсально: если body поддерживает to-поля пишем их
if (block.body instanceof BodyHasTarget tf) {
e.setToLogin(tf.toLogin());
e.setToBchName(tf.toBchName());
e.setToBlockGlobalNumber(tf.toBlockGlobalNumber());
e.setToBlockHashe(tf.toBlockHashe());
// optional: try compute to_login from target chain name (для индекса idx_blocks_to_target)
String toLogin = BlockchainNameUtil.loginFromBlockchainName(rb.toBlockchainName);
if (e.getToLogin() == null && e.getToBchName() != null) {
String toLogin = BlockchainNameUtil.loginFromBlockchainName(e.getToBchName());
if (toLogin != null && !toLogin.isBlank()) {
e.setToLogin(toLogin);
}
}
}
blocksDAO.upsert(c, e);
}