добавил новые типы связи - тоесть возможность добавлять убирать друга, контакт или подписку  (и тесты и всё работает)
This commit is contained in:
AidarKC 2026-01-06 00:24:24 +03:00
parent 94777c58c6
commit 7ba333bf6c
2 changed files with 77 additions and 9 deletions

View File

@ -12,17 +12,31 @@ import java.util.Objects;
* ConnectionBody type=3, ver=1. (Связь/отношение)
*
* Идея:
* - Это запись "у меня есть связь с X".
* - subType определяет вид связи:
* - Это запись "у меня есть связь с X" ИЛИ "я отменяю связь с X".
* - subType определяет вид связи и действие.
*
* subType (uint16):
* УСТАНОВИТЬ связь:
* 10 = FRIEND (друг)
* 20 = CONTACT (контакт)
* 30 = FOLLOW (подписан на кого-то)
*
* ОТМЕНИТЬ связь (событие, которое снимает прошлую связь):
* 11 = UNFRIEND (больше не друг)
* 21 = UNCONTACT (больше не контакт)
* 31 = UNFOLLOW (больше не подписан)
*
* Важно про смысл:
* - Состояние связи вычисляется по последнему блоку данной категории:
* (toLogin, kind=FRIEND/CONTACT/FOLLOW)
* Если последний subType 10/20/30 => связь активна
* Если последний subType 11/21/31 => связь снята
*
* Формат bodyBytes (BigEndian):
* [2] type=3
* [2] ver=1
*
* [2] subType (uint16) вид связи (10/20/30)
* [2] subType (uint16) вид связи (10,20/30)
*
* [1] toLoginLen (uint8)
* [N] toLogin UTF-8
@ -50,11 +64,16 @@ public final class ConnectionBody implements BodyRecord, BodyHasTarget {
/** Удобный ключ для BodyRecordParser: (type<<16)|ver */
public static final int KEY = ((TYPE & 0xFFFF) << 16) | (VER & 0xFFFF);
// subType:
// --- subType: SET ---
public static final short SUB_FRIEND = 10;
public static final short SUB_CONTACT = 20;
public static final short SUB_FOLLOW = 30;
// --- subType: UNSET (снятие/отмена связи) ---
public static final short SUB_UNFRIEND = 11; // больше не друг
public static final short SUB_UNCONTACT = 21; // больше не контакт
public static final short SUB_UNFOLLOW = 31; // больше не подписан
public final short subType;
/** С кем связь (главное поле). */
@ -162,7 +181,31 @@ public final class ConnectionBody implements BodyRecord, BodyHasTarget {
}
private static boolean isValidSubType(short st) {
return st == SUB_FRIEND || st == SUB_CONTACT || st == SUB_FOLLOW;
return st == SUB_FRIEND || st == SUB_CONTACT || st == SUB_FOLLOW
|| st == SUB_UNFRIEND || st == SUB_UNCONTACT || st == SUB_UNFOLLOW;
}
/** true если это событие установки связи (10/20/30). */
public boolean isSetAction() {
return subType == SUB_FRIEND || subType == SUB_CONTACT || subType == SUB_FOLLOW;
}
/** true если это событие снятия связи (11/21/31). */
public boolean isUnsetAction() {
return subType == SUB_UNFRIEND || subType == SUB_UNCONTACT || subType == SUB_UNFOLLOW;
}
/**
* Нормализованный вид связи без действия:
* FRIEND / CONTACT / FOLLOW
*/
public short kind() {
return switch (subType) {
case SUB_FRIEND, SUB_UNFRIEND -> SUB_FRIEND;
case SUB_CONTACT, SUB_UNCONTACT -> SUB_CONTACT;
case SUB_FOLLOW, SUB_UNFOLLOW -> SUB_FOLLOW;
default -> throw new IllegalStateException("Unexpected subType: " + (subType & 0xFFFF));
};
}
/* ===================================================================== */
@ -247,14 +290,27 @@ public final class ConnectionBody implements BodyRecord, BodyHasTarget {
case SUB_FRIEND -> "FRIEND (10)";
case SUB_CONTACT -> "CONTACT (20)";
case SUB_FOLLOW -> "FOLLOW (30)";
case SUB_UNFRIEND -> "UNFRIEND (11)";
case SUB_UNCONTACT -> "UNCONTACT (21)";
case SUB_UNFOLLOW -> "UNFOLLOW (31)";
default -> "UNKNOWN";
};
String action = isSetAction() ? "SET" : (isUnsetAction() ? "UNSET" : "?");
String kindStr = switch (kind()) {
case SUB_FRIEND -> "FRIEND";
case SUB_CONTACT -> "CONTACT";
case SUB_FOLLOW -> "FOLLOW";
default -> "?";
};
return """
ConnectionBody {
тип записи : CONNECTION (type=3, ver=1)
ожидаемая линия : 3
subType : %s
действие : %s
вид связи : %s
связь с login : "%s"
блокчейн друга/цели : "%s"
lastKnown globalNumber : %d
@ -262,6 +318,8 @@ public final class ConnectionBody implements BodyRecord, BodyHasTarget {
}
""".formatted(
st,
action,
kindStr,
toLogin,
toBlockchainName,
toBlockGlobalNumber,
@ -281,7 +339,7 @@ public final class ConnectionBody implements BodyRecord, BodyHasTarget {
}
/* ===================================================================== */
/* ====================== BodyToFields контракт ========================= */
/* ====================== BodyHasTarget контракт ========================= */
/* ===================================================================== */
@Override public String toLogin() { return toLogin; }

View File

@ -236,6 +236,16 @@ public class IT_03_AddBlock_NoAuth {
new byte[32]
), t);
// 6) USER2: Connection (UNFRIEND -> USER1) USER2 больше не друг USER1
if (TestConfig.DEBUG()) TestLog.stepTitle("USER2: Connection (UNFRIEND -> USER1)");
sender2.send(new ConnectionBody(
ConnectionBody.SUB_UNFRIEND,
TestConfig.LOGIN(), // to_login (USER1)
TestConfig.BCH_NAME(), // toBch (USER1 chain)
0,
new byte[32]
), t);
TestLog.pass("IT_03_AddBlock_NoAuth (combined): OK");
}