31 12 25
Сделал что бы запускалось. Поправил мелкие ошибки
This commit is contained in:
parent
62ea49d1fc
commit
f17d077f25
95
DOC/doc-BD.md
Normal file
95
DOC/doc-BD.md
Normal file
@ -0,0 +1,95 @@
|
||||
Документ: shine-server-bd — таблицы и структура
|
||||
Таблицы (что хранят)
|
||||
|
||||
solana_users — локальная таблица пользователей (логин + ключ устройства + опциональный solanaKey).
|
||||
|
||||
active_sessions — активные сессии пользователей (секреты сессии, время, push-подписки, IP/клиент-инфо).
|
||||
|
||||
users_params — сохранённые параметры пользователя (например, состояние просмотренности лент и прочие настройки), с подписью.
|
||||
|
||||
ip_geo_cache — кэш геолокации по IP (чтобы не дергать внешние сервисы каждый раз).
|
||||
|
||||
blockchain_state — агрегатное “текущее состояние” блокчейна по blockchainName (лимит, размер, последние хэши/номера).
|
||||
|
||||
blocks — сохранённые блоки/сообщения блокчейна (байты блока + связи “кому/куда” для адресации).
|
||||
|
||||
solana_users — пользователи и их ключи
|
||||
|
||||
login TEXT — логин пользователя (PRIMARY KEY)
|
||||
deviceKey TEXT — публичный ключ устройства (обязателен)
|
||||
solanaKey TEXT — дополнительный ключ Solana (может быть NULL)
|
||||
|
||||
active_sessions — активные сессии пользователя
|
||||
|
||||
sessionId TEXT — идентификатор сессии (PRIMARY KEY)
|
||||
login TEXT — логин владельца сессии (FK → solana_users.login)
|
||||
sessionPwd TEXT — пароль/секрет сессии (используется сервером)
|
||||
storagePwd TEXT — пароль/секрет для шифрования хранилища/данных
|
||||
sessionCreatedAtMs INTEGER — время создания сессии (ms)
|
||||
lastAuthirificatedAtMs INTEGER — время последней успешной аутентификации/refresh (ms)
|
||||
pushEndpoint TEXT — endpoint для web-push (nullable)
|
||||
pushP256dhKey TEXT — ключ p256dh для web-push (nullable)
|
||||
pushAuthKey TEXT — auth key для web-push (nullable)
|
||||
clientIp TEXT — IP клиента при auth/refresh (nullable)
|
||||
clientInfoFromClient TEXT — строка client-info от клиента (nullable)
|
||||
clientInfoFromRequest TEXT — строка client-info, собранная сервером (nullable)
|
||||
userLanguage TEXT — предпочитаемый язык пользователя (nullable)
|
||||
|
||||
users_params — параметры/состояния пользователя
|
||||
|
||||
login TEXT — логин владельца параметра (FK → solana_users.login)
|
||||
param TEXT — имя параметра (в паре с login образует UNIQUE)
|
||||
bch_channel_id INTEGER — id канала/ленты/контекста блокчейна (по умолчанию 0)
|
||||
value TEXT — значение параметра (nullable)
|
||||
time_ms INTEGER — время обновления параметра (ms)
|
||||
pubkey_num INTEGER — номер/индекс публичного ключа, которым подписано значение
|
||||
signature TEXT — подпись значения параметра (строка)
|
||||
|
||||
ip_geo_cache — кэш геоданных по IP
|
||||
|
||||
ip TEXT — IP-адрес (PRIMARY KEY)
|
||||
geo TEXT — строка гео-описания (“Country, City” и т.п.) (nullable)
|
||||
updated_at_ms INTEGER — время последнего обновления (ms)
|
||||
|
||||
blockchain_state — текущее состояние блокчейна по blockchainName
|
||||
|
||||
blockchainName TEXT — имя/идентификатор блокчейна (PRIMARY KEY)
|
||||
login TEXT — владелец блокчейна (FK → solana_users.login)
|
||||
blockchainKey TEXT — публичный ключ блокчейна (используется для подписи блоков)
|
||||
size_limit INTEGER — лимит размера блокчейн-файла (байты)
|
||||
file_size_bytes INTEGER — текущий размер файла блокчейна (байты)
|
||||
last_global_number INTEGER — номер последнего глобального блока (genesis обычно -1)
|
||||
last_global_hash TEXT — хэш последнего глобального блока (пусто для “нулевого” состояния)
|
||||
updated_at_ms INTEGER — время обновления состояния (ms)
|
||||
line0_last_number INTEGER — последний номер в линии 0
|
||||
line0_last_hash TEXT — последний хэш в линии 0
|
||||
line1_last_number INTEGER — последний номер в линии 1
|
||||
line1_last_hash TEXT — последний хэш в линии 1
|
||||
line2_last_number INTEGER — последний номер в линии 2
|
||||
line2_last_hash TEXT — последний хэш в линии 2
|
||||
line3_last_number INTEGER — последний номер в линии 3
|
||||
line3_last_hash TEXT — последний хэш в линии 3
|
||||
line4_last_number INTEGER — последний номер в линии 4
|
||||
line4_last_hash TEXT — последний хэш в линии 4
|
||||
line5_last_number INTEGER — последний номер в линии 5
|
||||
line5_last_hash TEXT — последний хэш в линии 5
|
||||
line6_last_number INTEGER — последний номер в линии 6
|
||||
line6_last_hash TEXT — последний хэш в линии 6
|
||||
line7_last_number INTEGER — последний номер в линии 7
|
||||
line7_last_hash TEXT — последний хэш в линии 7
|
||||
|
||||
blocks — блоки/сообщения блокчейна (байтовое тело + адресация)
|
||||
|
||||
login TEXT — владелец (FK → solana_users.login)
|
||||
bchName TEXT — имя блокчейна (FK → blockchain_state.blockchainName)
|
||||
blockGlobalNumber INTEGER — глобальный номер блока
|
||||
blockGlobalPreHashe TEXT — предыдущий глобальный хэш (строка)
|
||||
blockLineIndex INTEGER — индекс линии (0..7)
|
||||
blockLineNumber INTEGER — номер блока внутри линии
|
||||
blockLinePreHashe TEXT — предыдущий хэш внутри линии
|
||||
msgType INTEGER — тип сообщения/записи (код)
|
||||
blockByte BLOB — сырые байты блока (nullable)
|
||||
to_login TEXT — адресат логин (nullable)
|
||||
toBchName TEXT — адресат блокчейн (nullable)
|
||||
toBlockGlobalNumber INTEGER — целевой глобальный номер (nullable)
|
||||
toBlockHashe TEXT — целевой хэш (nullable)
|
||||
23
DOC/doc_all_libs.md
Normal file
23
DOC/doc_all_libs.md
Normal file
@ -0,0 +1,23 @@
|
||||
Перечень библиотек и их краткое описание
|
||||
|
||||
shine-server-log
|
||||
Статический “сиренный” метод для максимально заметного критического лога администратору
|
||||
|
||||
shine-server-config
|
||||
Минимальный конфиг-лоадер, который один раз читает application.properties и даёт доступ к параметрам.
|
||||
Внешние настройки (2): server.1port=7070, db.path=data/shine.sqlite.
|
||||
|
||||
shine-server-geo
|
||||
Утилиты, которые вытаскивают IP/язык/UA из Jetty WebSocket и (опционально) резолвят гео по IP с кэшем в БД.
|
||||
|
||||
shine-server-crypto
|
||||
Базовые крипто-утилиты для SHA-256 и Ed25519 (BouncyCastle) + проверка подписи/хэша для .bch сущностей и маленький self-test.
|
||||
|
||||
shine-server-bd
|
||||
Библиотека реалезующая всю работу с БД:
|
||||
|
||||
shine-server-blockchain
|
||||
Библиотека, которая задаёт единый бинарный формат блоков (RAW+signature+hash), парсит/валидирует “тело” блока по type/version, и проверяет целостность/подпись цепочки через SHA-256 + Ed25519 с привязкой к login и предыдущим хэшам.
|
||||
|
||||
shine-server-protocol
|
||||
Библиотека JSON-протокол поверх WebSocket для взаимодействия с клиентами.
|
||||
17
DOC/libs/shine-server-bd/DOC.md
Normal file
17
DOC/libs/shine-server-bd/DOC.md
Normal file
@ -0,0 +1,17 @@
|
||||
shine-server-bd — это библиотека реалезующая всю работу с БД:
|
||||
|
||||
хранит пользователей/сессии/параметры/кэш IP→гео и данные блокчейна (состояние + блоки), предоставляя единый SqliteDbController для соединений, набор DAO под каждую таблицу (Singleton, методы с Connection для транзакций и без Connection — сами открывают/закрывают), и простые entity-модели как контейнеры данных для маппинга ResultSet↔Java.
|
||||
|
||||
Логика структуры классов (в двух словах):
|
||||
|
||||
shine.db.SqliteDbController — один вход в БД: читает db.path, при отсутствии файла создаёт БД, выдаёт новые Connection и настраивает PRAGMA.
|
||||
shine.db.DatabaseInitializer — разовая сборка схемы (таблицы + индексы).
|
||||
|
||||
|
||||
shine.db.entities.* — POJO-модели строк таблиц (без логики, только поля/геттеры/сеттеры + иногда удобные методы вроде getDeviceKeyByte()).
|
||||
shine.db.dao.* — DAO по таблицам: ActiveSessionsDAO, SolanaUsersDAO, UserParamsDAO, IpGeoCacheDAO, BlockchainStateDAO, BlocksDAO; плюс “сервисные” DAO:
|
||||
|
||||
UserCreateDAO — атомарная регистрация пользователя в транзакции (BEGIN IMMEDIATE + rollback/commit).
|
||||
// Временное решение позволяющее регистрировать новых пользователей
|
||||
// атомарно и добавляет запись и в solana_users и в BlockchainState
|
||||
|
||||
85
DOC/libs/shine-server-blockchain/Doc.md
Normal file
85
DOC/libs/shine-server-blockchain/Doc.md
Normal file
@ -0,0 +1,85 @@
|
||||
shine-server-blockchain — это библиотека, которая задаёт формат блока, правила парсинга/валидации тела, крипто-проверку (hash+Ed25519) и безопасную работу с файлами блокчейна (data/<name>.bch через временный .tmp_bch).
|
||||
|
||||
Как устроена структура и логика работы
|
||||
|
||||
1) “Блок” как центральный объект (ядро)
|
||||
BchBlockEntry — единая модель блока “как лежит на диске/в сети”:
|
||||
читает/собирает байты в формате RAW + signature64 + hash32
|
||||
сразу парсит body через BodyRecordParser
|
||||
сразу проверяет что lineIndex совпадает с тем, что ожидает конкретный тип body (expectedLineIndex())
|
||||
То есть: всё, что считается “блоком”, обязано быть самодостаточно валидным уже на этапе создания объекта.
|
||||
|
||||
2) “Body” как плагины по типам (расширяемая часть) ! <-- Новые типы записей добавлть сюда !
|
||||
BodyRecord — интерфейс контракта для всех тел:
|
||||
type/version — идентификаторы формата
|
||||
expectedLineIndex() — жёсткое правило “в какой линии может жить”
|
||||
check() — логическая валидация содержимого
|
||||
toBytes() — сериализация обратно в бинарь
|
||||
|
||||
BodyRecordParser — диспетчер: читает первые 4 байта (type+ver) и выбирает нужный класс:
|
||||
HeaderBody (lineIndex=0)
|
||||
TextBody (lineIndex=1)
|
||||
ReactionBody (lineIndex=2)
|
||||
|
||||
Добавление нового типа = добавить новый класс XxxBody + кейс в BodyRecordParser.
|
||||
|
||||
3) Криптография как отдельный слой проверки
|
||||
BchCryptoVerifier отвечает за “как получить хэш и как проверить подпись”:
|
||||
строит preimage = "SHiNE" + login + prevGlobalHash32 + prevLineHash32 + rawBytes
|
||||
считает sha256(preimage) и сравнивает с hash32 внутри блока
|
||||
проверяет Ed25519 подпись над hash32
|
||||
Важно: BchBlockEntry не проверяет подпись — он проверяет структуру блока и правильность body/lineIndex, а криптопроверка вынесена отдельно.
|
||||
|
||||
4) Утилиты вокруг имени и файлов
|
||||
|
||||
BlockchainNameUtil — извлекает login из blockchainName (отрезает 3 символа суффикса).
|
||||
FileStoreUtil — безопасное файловое хранилище:
|
||||
|
||||
|
||||
5) Объяснение структуры работы
|
||||
|
||||
Типичный сценарий: пришёл блок → проверить → принять
|
||||
Шаг 0. Контекст (что у нас уже есть снаружи)
|
||||
|
||||
Снаружи библиотеки (в сервере) у тебя уже известны:
|
||||
userLogin — владелец блокчейна
|
||||
publicKey32 — публичный ключ пользователя
|
||||
prevGlobalHash32 — хэш предыдущего блока по глобальной цепи
|
||||
prevLineHash32 — хэш предыдущего блока по текущей линии
|
||||
|
||||
Библиотека не хранит это сама, она ожидает, что сервер это передаст.
|
||||
|
||||
Шаг 1. Парсинг блока (структура + логика)
|
||||
BchBlockEntry block = new BchBlockEntry(fullBytes);
|
||||
|
||||
|
||||
Что происходит здесь автоматически:
|
||||
проверяется длина блока
|
||||
проверяется recordSize
|
||||
парсится RAW-заголовок
|
||||
парсится body через BodyRecordParser
|
||||
проверяется, что lineIndex соответствует типу body
|
||||
(HEADER → line 0, TEXT → line 1, REACTION → line 2 и т.д.)
|
||||
❗ На этом шаге никакой криптографии ещё нет — только структура и логика формата.
|
||||
|
||||
Если тут не упало исключение → блок структурно корректен.
|
||||
|
||||
Шаг 2. Подготовка данных для криптопроверки (они получаются просто из частей байтов полного блокас подписью)
|
||||
byte[] rawBytes = block.getRawBytes();
|
||||
byte[] signature64 = block.getSignature64();
|
||||
byte[] hash32FromTail = block.getHash32();
|
||||
|
||||
Важно:
|
||||
rawBytes — это ровно те байты, которые участвовали в хэшировании
|
||||
hash32FromTail — это то, что автор блока положил внутрь блока
|
||||
|
||||
Шаг 3. Криптографическая проверка (ключевой вызов)
|
||||
boolean ok = BchCryptoVerifier.verifyAll(
|
||||
userLogin,
|
||||
prevGlobalHash32,
|
||||
prevLineHash32,
|
||||
rawBytes,
|
||||
signature64,
|
||||
publicKey32,
|
||||
hash32FromTail
|
||||
);
|
||||
48
DOC/libs/shine-server-blockchain/Общая структура блока.md
Normal file
48
DOC/libs/shine-server-blockchain/Общая структура блока.md
Normal file
@ -0,0 +1,48 @@
|
||||
Общая структура блока
|
||||
|
||||
Блок — это бинарная запись фиксированного формата:
|
||||
|
||||
[ RAW ][ signature64 ][ hash32 ]
|
||||
|
||||
RAW — данные блока (участвуют в хэшировании и подписи)
|
||||
signature64 — Ed25519-подпись над hash32
|
||||
hash32 — SHA-256 от preimage (привязан к цепочке и владельцу)
|
||||
|
||||
RAW-часть (BigEndian)
|
||||
recordSize int32 — размер RAW (без signature+hash)
|
||||
recordNumber int32 — глобальный номер блока
|
||||
timestamp int64 — unix time (seconds)
|
||||
lineIndex int16 — индекс линии
|
||||
lineNumber int32 — номер блока внутри линии
|
||||
bodyBytes bytes — тело блока (type+version+payload)
|
||||
|
||||
Общая структура блокчейна
|
||||
|
||||
Блокчейн — это:
|
||||
линейная цепочка блоков (по recordNumber)
|
||||
внутри неё — параллельные логические линии (lineIndex)
|
||||
каждая линия имеет собственную нумерацию (lineNumber) и prevLineHash
|
||||
вся цепочка связана ещё и prevGlobalHash
|
||||
|
||||
👉 Таким образом, каждый блок:
|
||||
связан с предыдущим глобальным блоком
|
||||
и с предыдущим блоком своей линии
|
||||
|
||||
Это даёт:
|
||||
строгий порядок всей истории
|
||||
и независимую валидацию логических потоков
|
||||
|
||||
Криптографический смысл блока
|
||||
|
||||
Хэш блока считается от:
|
||||
"SHiNE" +
|
||||
login +
|
||||
prevGlobalHash32 +
|
||||
prevLineHash32 +
|
||||
RAW
|
||||
|
||||
Это означает:
|
||||
блок жёстко привязан к владельцу (login)
|
||||
блок невозможно перенести в другую цепочку
|
||||
подмена предыдущего блока ломает всю цепь
|
||||
Подпись Ed25519 делается над этим хэшем.
|
||||
36
DOC/libs/shine-server-blockchain/Формат существующих Body.md
Normal file
36
DOC/libs/shine-server-blockchain/Формат существующих Body.md
Normal file
@ -0,0 +1,36 @@
|
||||
Формат и смысл существующих Body
|
||||
|
||||
1) HeaderBody (type=0, ver=1)
|
||||
|
||||
Линия: lineIndex = 0
|
||||
Смысл:
|
||||
Генезис-блок блокчейна, объявляет формат и владельца.
|
||||
|
||||
Содержит:
|
||||
сигнатуру формата "SHiNE"
|
||||
login владельца блокчейна
|
||||
👉 Всегда первый блок, всегда в линии 0.
|
||||
|
||||
2) TextBody (type=1, ver=1)
|
||||
|
||||
Линия: lineIndex = 1
|
||||
Смысл:
|
||||
Основной контент — текстовые записи (посты, сообщения, дневник).
|
||||
|
||||
Содержит:
|
||||
UTF-8 текст произвольной длины
|
||||
👉 Это “основная история” блокчейна пользователя.
|
||||
|
||||
3) ReactionBody (type=2, ver=1)
|
||||
|
||||
Линия: lineIndex = 2
|
||||
Смысл:
|
||||
Связь с другим блокчейном или блоком (реакция, ответ, лайк, ссылка).
|
||||
|
||||
Содержит:
|
||||
код реакции
|
||||
имя целевого блокчейна
|
||||
globalNumber целевого блока
|
||||
hash32 целевого блока
|
||||
👉 Это механизм межблокчейн-связей без изменения чужих цепочек.
|
||||
|
||||
7
DOC/libs/shine-server-config/doc.md
Normal file
7
DOC/libs/shine-server-config/doc.md
Normal file
@ -0,0 +1,7 @@
|
||||
shine-server-config
|
||||
|
||||
Минимальная библиотека конфигурации, предоставляющая потокобезопасный singleton-доступ к параметрам из application.properties.
|
||||
|
||||
Настройки:
|
||||
server.port=7070 — порт запуска сервера
|
||||
db.path=data/shine.sqlite — путь к SQLite базе данных
|
||||
8
DOC/libs/shine-server-crypto/DOC.md
Normal file
8
DOC/libs/shine-server-crypto/DOC.md
Normal file
@ -0,0 +1,8 @@
|
||||
shine-server-crypto
|
||||
|
||||
О чём: базовые крипто-утилиты для SHA-256 и Ed25519 (BouncyCastle) + проверка подписи/хэша для .bch сущностей и маленький self-test.
|
||||
Внешние методы, которые вызываются:
|
||||
BchCryptoVerifier.verifyAll(), BchCryptoVerifier.buildPreimage(), Ed25519Util.generatePrivateKey(), Ed25519Util.generatePrivateKeyFromString(), Ed25519Util.derivePublicKey(), Ed25519Util.sign(), Ed25519Util.verify(), Ed25519Util.keyToBase64(), Ed25519Util.keyFromBase64(),
|
||||
HashSHA256Util.sha256()
|
||||
|
||||
HashSHA256Util.loginToLoginId(), HashSHA256Util.loginIdFromLogin(),
|
||||
19
DOC/libs/shine-server-geo/DOC.md
Normal file
19
DOC/libs/shine-server-geo/DOC.md
Normal file
@ -0,0 +1,19 @@
|
||||
shine-server-geo
|
||||
|
||||
Назначение: утилиты для получения “кто подключился” (IP/UA/язык) и геолокации по IP (с опциональным кэшем в БД).
|
||||
|
||||
Классы:
|
||||
|
||||
ClientInfoService — собирает строку UA/ch-ua/platform/mobile/remoteIP, вытаскивает реальный IP (приоритет: X-Forwarded-For → X-Real-IP → remoteAddress), парсит первый Accept-Language.
|
||||
GeoLookupService — геолокация по IP через внешний API (ip-api.com), умеет вариант без кэша и с кэшем в таблице ip_geo_cache через IpGeoCacheDAO (пишет даже unknown), плюс метод получения внешнего IP через api.ipify.org.
|
||||
GeoLookupTestMain — консольный тест: берёт IP из аргумента или определяет внешний, вызывает геолокацию и печатает результат + время.
|
||||
|
||||
|
||||
Внешние (публично используемые) методы:
|
||||
|
||||
ClientInfoService.buildClientInfoString(Session) — формирует строку с User-Agent, client-hints и реальным IP клиента
|
||||
ClientInfoService.extractClientIp(Session) — извлекает реальный IP (X-Forwarded-For / X-Real-IP / remoteAddress)
|
||||
ClientInfoService.extractPreferredLanguageTag(Session) — возвращает основной язык клиента из Accept-Language
|
||||
GeoLookupService.resolveCountryCityOrIp(String ip) — геолокация по IP без кэша (Country, City или unknown)
|
||||
GeoLookupService.resolveCountryCityOrIpWithCache(String ip) — геолокация по IP с кэшированием в БД
|
||||
GeoLookupService.fetchPublicIpOrDefault(String fallbackIp) — получение внешнего IP текущей машины
|
||||
10
DOC/libs/shine-server-log/DOC.md
Normal file
10
DOC/libs/shine-server-log/DOC.md
Normal file
@ -0,0 +1,10 @@
|
||||
shine-log (BlockchainAdminNotifier)
|
||||
|
||||
Суть (1 предложение): единая точка для “красного” оповещения админа о критических проблемах консистентности, сейчас — через максимально заметный log.error, позже — через Telegram/email/webhook и т.п.
|
||||
|
||||
Структура (очень кратко):
|
||||
|
||||
BlockchainAdminNotifier (final utility)
|
||||
|
||||
BlockchainAdminNotifier.critical(String message)
|
||||
BlockchainAdminNotifier.critical(String message, Throwable t)
|
||||
@ -1,205 +0,0 @@
|
||||
формат добавления блоков и из чего реально состоит блок, плюс как именно считаются хэши и подписи.
|
||||
|
||||
1) Формат добавления блоков в файл .bch
|
||||
|
||||
Файл — это просто конкатенация блоков один за другим, без разделителей:
|
||||
|
||||
BLOCK_0 | BLOCK_1 | BLOCK_2 | ...
|
||||
|
||||
|
||||
Чтобы читать файл, ты идёшь по нему последовательно:
|
||||
|
||||
Читаешь первые 4 байта = recordSize
|
||||
|
||||
Понимаешь, сколько всего байт занимает блок:
|
||||
|
||||
fullBlockLen = recordSize + 64 + 32
|
||||
|
||||
|
||||
Считываешь оставшиеся байты блока и парсишь:
|
||||
|
||||
RAW часть длиной recordSize
|
||||
|
||||
затем signature64
|
||||
|
||||
затем hash32
|
||||
|
||||
Это удобно тем, что файл можно дописывать (APPEND) хоть по сети, хоть локально: блоки самодостаточные.
|
||||
|
||||
2) Из чего состоит блок (формат блока)
|
||||
2.1. RAW (участвует в preimage и верификации; подпись/хэш к нему «пришиты»)
|
||||
|
||||
BigEndian, фиксированный заголовок + body:
|
||||
|
||||
RAW:
|
||||
|
||||
[4] recordSize (int) — размер RAW включая эти 4 байта, но без signature+hash
|
||||
|
||||
[4] recordNumber (int) — глобальный номер блока (цепочка)
|
||||
|
||||
[8] timestamp (long) — unix seconds
|
||||
|
||||
[2] line (short) — линия (у вас пока по сути одна)
|
||||
|
||||
[4] lineNumber (int) — номер в линии (у вас пока обычно равен global)
|
||||
|
||||
[N] bodyBytes — тело, начинается с [2] type + [2] version, дальше payload
|
||||
|
||||
RAW_HEADER_SIZE = 4 + 4 + 8 + 2 + 4 = 22 байта
|
||||
|
||||
2.2. TAIL (не входит в recordSize)
|
||||
|
||||
[64] signature64 — Ed25519 подпись
|
||||
|
||||
[32] hash32 — SHA-256 хэш
|
||||
|
||||
Итого полный блок:
|
||||
|
||||
FULL = RAW(recordSize bytes) + signature64 + hash32
|
||||
|
||||
3) Формат body (тела блока)
|
||||
|
||||
У тебя правило железное: каждый body начинается одинаково:
|
||||
|
||||
[2] type
|
||||
|
||||
[2] version
|
||||
|
||||
дальше payload по типу/версии
|
||||
|
||||
Парсер делает ключ:
|
||||
|
||||
key = (type<<16) | version
|
||||
|
||||
3.1 HeaderBody (type=0, ver=1)
|
||||
|
||||
Полный bodyBytes:
|
||||
|
||||
[2] type=0
|
||||
|
||||
[2] ver=1
|
||||
|
||||
[8] tag "SHiNE001" (ASCII)
|
||||
|
||||
[1] loginLength (uint8)
|
||||
|
||||
[N] login UTF-8
|
||||
|
||||
Это «генезис-смысл» для идентичности: в теле блока явно хранится логин.
|
||||
|
||||
3.2 TextBody (type=1, ver=1)
|
||||
|
||||
[2] type=1
|
||||
|
||||
[2] ver=1
|
||||
|
||||
[N] message UTF-8
|
||||
|
||||
4) Как считается хэш (hash32)
|
||||
|
||||
Важно: hash32 в блоке — это не hash(rawBytes).
|
||||
|
||||
Ты считаешь:
|
||||
|
||||
4.1 Preimage
|
||||
preimage =
|
||||
"SHiNE" +
|
||||
[1] loginLen + loginBytes(UTF-8) +
|
||||
prevGlobalHash32 +
|
||||
prevLineHash32 +
|
||||
rawBytes
|
||||
|
||||
|
||||
Где:
|
||||
|
||||
"SHiNE" — доменная метка (защита от «подпиши этим же ключом что-то другое»)
|
||||
|
||||
loginLen + loginBytes — привязка блока к пользователю/цепочке
|
||||
|
||||
prevGlobalHash32 — сцепление по глобальной цепи
|
||||
|
||||
prevLineHash32 — сцепление по линии
|
||||
|
||||
rawBytes — содержимое текущего блока без подписи/хэша
|
||||
|
||||
4.2 Сам хэш
|
||||
hash32 = SHA-256(preimage)
|
||||
|
||||
|
||||
И именно этот hash32 должен лежать в конце блока.
|
||||
|
||||
5) Как считается подпись (signature64)
|
||||
|
||||
Подписывается не rawBytes, а hash32:
|
||||
|
||||
signature64 = Ed25519.sign(hash32, privateKey)
|
||||
|
||||
|
||||
Проверка:
|
||||
|
||||
Пересобираем preimage
|
||||
|
||||
Считаем hash32 = sha256(preimage)
|
||||
|
||||
Сверяем hash32 с тем, что лежит в блоке
|
||||
|
||||
Проверяем подпись:
|
||||
|
||||
Ed25519.verify(hash32, signature64, publicKey32)
|
||||
|
||||
|
||||
Это хорошая схема: подпись всегда фиксированного размера, а хэш — единая точка правды.
|
||||
|
||||
6) Что является «цепочкой» и чем блоки сцеплены
|
||||
|
||||
Сцепление идёт через prevGlobalHash32 и prevLineHash32, которые ты передаёшь в verifyAll(...).
|
||||
|
||||
То есть логика добавления нового блока (в терминах данных) такая:
|
||||
|
||||
берём последний блок
|
||||
|
||||
достаём его hash32
|
||||
|
||||
это и будет prevGlobalHash32 для нового блока
|
||||
|
||||
prevLineHash32 — по той линии, куда добавляем (у вас пока это то же самое, потому что одна линия/нет разветвления)
|
||||
|
||||
У тебя даже отдельно отмечено: пока нет отдельных линий, lastLineHash == lastGlobalHash — значит сейчас обе цепочки фактически совпадают.
|
||||
|
||||
7) Мини-схема “как добавить новый блок” (пошагово)
|
||||
|
||||
Собрать BodyRecord → получить bodyBytes = body.toBytes()
|
||||
|
||||
Собрать RAW:
|
||||
|
||||
recordNumber = lastRecordNumber + 1
|
||||
|
||||
timestamp = nowSeconds
|
||||
|
||||
line (скорее всего 0 или 1 — как вы договорились)
|
||||
|
||||
lineNumber = lastLineNumber + 1 (сейчас равно global)
|
||||
|
||||
recordSize = RAW_HEADER_SIZE + bodyBytes.length
|
||||
|
||||
rawBytes = new BchBlockEntry(...).getRawBytes() (или собрать вручную)
|
||||
|
||||
preimage = buildPreimage(login, prevGlobalHash32, prevLineHash32, rawBytes)
|
||||
|
||||
hash32 = sha256(preimage)
|
||||
|
||||
signature64 = Ed25519.sign(hash32, privateKey)
|
||||
|
||||
Собрать финальный BchBlockEntry(..., signature64, hash32)
|
||||
|
||||
Дописать toBytes() в файл .bch
|
||||
|
||||
8) Важные нюансы (чтобы не словить «тихий баг»)
|
||||
|
||||
recordSize включает себя (первые 4 байта) — это ок, просто помнить.
|
||||
|
||||
bodyLen = recordSize - RAW_HEADER_SIZE — значит RAW_HEADER_SIZE обязан быть всегда синхронен с реальным RAW.
|
||||
|
||||
login в preimage ограничен 255 байт (у тебя [1] loginLen) — это правильно и предсказуемо.
|
||||
|
||||
В HeaderBody tag фиксирован "SHiNE001" — фактически версия протокола body-header’а.
|
||||
@ -11,7 +11,7 @@ import java.util.Objects;
|
||||
* Полный bodyBytes:
|
||||
* [2] type=0
|
||||
* [2] version=1
|
||||
* [8] tag ASCII "SHiNE001"
|
||||
* [8] tag ASCII "SHiNE"
|
||||
* [1] loginLength=N (uint8)
|
||||
* [N] login UTF-8
|
||||
*
|
||||
@ -23,9 +23,9 @@ public final class HeaderBody implements BodyRecord {
|
||||
public static final short TYPE = 0;
|
||||
public static final short VER = 1;
|
||||
|
||||
public static final String TAG = "SHiNE001";
|
||||
public static final String TAG = "SHiNE";
|
||||
|
||||
public final String tag; // "SHiNE001"
|
||||
public final String tag; // "SHiNE"
|
||||
public final String login;
|
||||
|
||||
/** Десериализация из полного bodyBytes (включая type/version). */
|
||||
@ -42,7 +42,7 @@ public final class HeaderBody implements BodyRecord {
|
||||
if (bb.remaining() < 8 + 1)
|
||||
throw new IllegalArgumentException("Header payload too short");
|
||||
|
||||
byte[] tagBytes = new byte[8];
|
||||
byte[] tagBytes = new byte[5];
|
||||
bb.get(tagBytes);
|
||||
String t = new String(tagBytes, StandardCharsets.US_ASCII);
|
||||
if (!TAG.equals(t)) throw new IllegalArgumentException("Bad tag: " + t);
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
# utils.files
|
||||
|
||||
Хранение блокчейнов в виде файлов в папке `data/`.
|
||||
|
||||
---
|
||||
|
||||
## FileStoreUtil
|
||||
Singleton для чтения и записи `.bch` файлов.
|
||||
|
||||
- `newBlockchain(id, data)` — создать новый файл `data/<id>.bch`
|
||||
- `addDataToBlockchain(id, data)` — добавить байты в конец файла
|
||||
- `readAllDataFromBlockchain(id)` — прочитать весь файл как массив байт
|
||||
|
||||
Каждый файл содержит последовательность полных блоков `[RAW][signature64][hash32]...`
|
||||
|
||||
---
|
||||
|
||||
## FileStoreUtilSelfTest
|
||||
Тест: создаёт, дописывает и читает файл, чтобы проверить корректность.
|
||||
|
||||
---
|
||||
|
||||
Пока используется как временное файловое хранилище.
|
||||
В будущем всё это уйдёт в SQL.
|
||||
|
||||
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
# utils.search
|
||||
|
||||
Поиск пользователей по логину среди зарегистрированных блокчейнов.
|
||||
|
||||
---
|
||||
|
||||
## UserSearchService
|
||||
Singleton-сервис для поиска первых 5 логинов, содержащих подстроку (без учёта регистра).
|
||||
|
||||
Основные методы:
|
||||
- `searchFirst5(String query)` — вернуть список `Pair(id, login)`
|
||||
- `packPair(Pair p)` — упаковать пару в бинарный ответ `[8]id + [1]len + [len]login`
|
||||
|
||||
Используется сервером в операции `SEARCH_USERS (op=30)` для ответа клиенту.
|
||||
16
shine-server-crypto/concat_to_file.sh
Executable file
16
shine-server-crypto/concat_to_file.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
OUTFILE="all_files.txt"
|
||||
|
||||
# очищаем или создаём файл
|
||||
: > "$OUTFILE"
|
||||
|
||||
# собрать только *.java файлы и вывести их содержимое в файл
|
||||
find . -type f -name "*.java" | sort | while read -r f; do
|
||||
cat "$f" >> "$OUTFILE"
|
||||
echo >> "$OUTFILE" # пустая строка-разделитель
|
||||
done
|
||||
|
||||
echo "Готово! Все .java файлы собраны в $OUTFILE"
|
||||
|
||||
@ -18,42 +18,6 @@ public final class HashSHA256Util {
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Получить loginId из строки логина.
|
||||
* Алгоритм:
|
||||
* - login -> UTF-8 bytes
|
||||
* - SHA-256
|
||||
* - берём последние 8 байт (справа)
|
||||
* - интерпретируем как signed long (BigEndian)
|
||||
*/
|
||||
public static long loginToLoginId(String login) {
|
||||
if (login == null || login.isBlank())
|
||||
throw new IllegalArgumentException("login is null or empty");
|
||||
|
||||
byte[] hash = sha256(login.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// последние 8 байт SHA-256
|
||||
return ByteBuffer.wrap(hash, 24, 8)
|
||||
.order(ByteOrder.BIG_ENDIAN)
|
||||
.getLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* loginId = last 8 bytes of sha256(login UTF-8), big-endian.
|
||||
* (берём 8 байт справа и читаем как unsigned long в BE)
|
||||
*/
|
||||
public static long loginIdFromLogin(String login) {
|
||||
if (login == null || login.isBlank())
|
||||
throw new IllegalArgumentException("login is blank");
|
||||
|
||||
byte[] h = sha256(login.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
long v = 0;
|
||||
for (int i = 24; i < 32; i++) {
|
||||
v = (v << 8) | (h[i] & 0xFFL);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/** Инкрементальный SHA-256 (если нужно будет кормить по кускам). */
|
||||
public static final class Sha256 {
|
||||
private final SHA256Digest d = new SHA256Digest();
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
package shine.db.dao;
|
||||
|
||||
import shine.db.SqliteDbController;
|
||||
import shine.db.entities.BlockchainStateEntry;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/**
|
||||
* SolanaBlockchainsDAO — таблица блокчейнов пользователя.
|
||||
*
|
||||
* Сейчас физически это blockchain_state, потому что:
|
||||
* - у одного login может быть несколько blockchainName
|
||||
* - у каждого blockchainName свой blockchainKey и size_limit
|
||||
*
|
||||
* Правило:
|
||||
* - методы с Connection НЕ закрывают соединение
|
||||
* - методы без Connection сами открывают и закрывают соединение
|
||||
*/
|
||||
public final class SolanaBlockchainsDAO {
|
||||
|
||||
private static volatile SolanaBlockchainsDAO instance;
|
||||
private final SqliteDbController db = SqliteDbController.getInstance();
|
||||
private final BlockchainStateDAO stateDao = BlockchainStateDAO.getInstance();
|
||||
|
||||
private SolanaBlockchainsDAO() {}
|
||||
|
||||
public static SolanaBlockchainsDAO getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (SolanaBlockchainsDAO.class) {
|
||||
if (instance == null) instance = new SolanaBlockchainsDAO();
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public BlockchainStateEntry getByBlockchainName(String blockchainName) throws SQLException {
|
||||
return stateDao.getByBlockchainName(blockchainName);
|
||||
}
|
||||
|
||||
public BlockchainStateEntry getByBlockchainName(Connection c, String blockchainName) throws SQLException {
|
||||
return stateDao.getByBlockchainName(c, blockchainName);
|
||||
}
|
||||
|
||||
/** Для HEADER: проверка, что blockchain_state существует и last_global_number=-1. */
|
||||
public BlockchainStateEntry requireExistingAtGenesis(Connection c, String blockchainName) throws SQLException {
|
||||
return stateDao.requireExistingAtGenesis(c, blockchainName);
|
||||
}
|
||||
|
||||
/** Для добавления блока: атомарная проверка лимита + увеличение размера файла. */
|
||||
public boolean tryIncreaseFileSizeWithinLimit(Connection c, String blockchainName, long deltaBytes, long nowMs) throws SQLException {
|
||||
return stateDao.tryIncreaseFileSizeWithinLimit(c, blockchainName, deltaBytes, nowMs);
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
# Структура БД SHiNE (кратко)
|
||||
|
||||
## Таблица `solana_users`
|
||||
Локальная копия данных о пользователях из Solana.
|
||||
|
||||
Поля:
|
||||
- `login` (TEXT) — логин пользователя.
|
||||
- `loginId` (INTEGER, PK) — ID пользователя, основной ключ.
|
||||
- `bchId` (INTEGER) — ID блокчейна пользователя.
|
||||
- `pubkey0` (TEXT) — первый публичный ключ.
|
||||
- `pubkey1` (TEXT) — второй публичный ключ.
|
||||
- `bchLimit` (INTEGER, NULL) — произвольный лимит для пользователя (опционально).
|
||||
|
||||
---
|
||||
|
||||
## Таблица `active_sessions`
|
||||
Активные сессии пользователей (WebSocket/WSS + Web Push).
|
||||
|
||||
Поля:
|
||||
- `sessionId` (INTEGER, PK) — ID сессии, генерируется приложением.
|
||||
- `session_pwd` (TEXT) — секрет/пароль сессии.
|
||||
- `loginId` (INTEGER, FK → solana_users.loginId) — владелец сессии.
|
||||
- `time_ms` (INTEGER) — время создания/активности сессии (мс от эпохи).
|
||||
- `pubkey_num` (INTEGER) — номер ключа пользователя, которым подписывались данные.
|
||||
- `push_endpoint` (TEXT, NULL) — endpoint Web Push.
|
||||
- `push_p256dh_key` (TEXT, NULL) — p256dh-ключ Web Push.
|
||||
- `push_auth_key` (TEXT, NULL) — auth-ключ Web Push.
|
||||
|
||||
---
|
||||
|
||||
## Таблица `users_params`
|
||||
Сохранённые параметры и состояния пользователя (например, до какого сообщения прочитана лента).
|
||||
|
||||
Поля:
|
||||
- `loginId` (INTEGER, FK → solana_users.loginId) — пользователь.
|
||||
- `param` (TEXT) — имя параметра (ключ).
|
||||
- `bch_channel_id` (INTEGER, DEFAULT 0) — ID канала/ленты который просмотрен.
|
||||
- `value` (TEXT, NULL) — значение параметра (строка).
|
||||
- `time_ms` (INTEGER) — время последнего обновления (мс от эпохи).
|
||||
- `pubkey_num` (INTEGER) — номер ключа, которым подписано значение.
|
||||
- `signature` (TEXT, NULL) — подпись значения.
|
||||
|
||||
Ограничения:
|
||||
- `UNIQUE(loginId, param)` — у одного пользователя каждый `param` только один раз.
|
||||
16
shine-server-log/concat_to_file.sh
Executable file
16
shine-server-log/concat_to_file.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
OUTFILE="all_files.txt"
|
||||
|
||||
# очищаем или создаём файл
|
||||
: > "$OUTFILE"
|
||||
|
||||
# собрать только *.java файлы и вывести их содержимое в файл
|
||||
find . -type f -name "*.java" | sort | while read -r f; do
|
||||
cat "$f" >> "$OUTFILE"
|
||||
echo >> "$OUTFILE" # пустая строка-разделитель
|
||||
done
|
||||
|
||||
echo "Готово! Все .java файлы собраны в $OUTFILE"
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
package server.logic.ws_protocol.JSON;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_AuthChallenge_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_CreateAuthSession_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_RefreshSession_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_CloseActiveSession_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_ListSessions_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.blockchain.Net_AddBlock_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.tempToTest.Net_AddUser_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.*;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.entyties.*;
|
||||
import server.logic.ws_protocol.JSON.handlers.blockchain.entyties.*;
|
||||
import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.*;
|
||||
import server.logic.ws_protocol.JSON.handlers.blockchain.entyties.Net_AddBlock_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_AddUser_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.Net_AuthChallenge_Handler;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.Net_CreateAuthSession__Handler;
|
||||
|
||||
@ -2,8 +2,7 @@ package server.logic.ws_protocol.JSON.handlers.auth;
|
||||
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.*;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_AuthChallenge_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_AuthChallenge_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.entyties.*;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
|
||||
@ -4,8 +4,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_CloseActiveSession_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_CloseActiveSession_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.entyties.*;
|
||||
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;
|
||||
|
||||
@ -5,10 +5,9 @@ import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_CreateAuthSession_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.entyties.*;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_CreateAuthSession_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
|
||||
@ -3,13 +3,12 @@ package server.logic.ws_protocol.JSON.handlers.auth;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_ListSessions_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_ListSessions_Response;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_ListSessions_Response.SessionInfo;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.entyties.*;
|
||||
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.utils.NetExceptionResponseFactory;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.entyties.Net_ListSessions_Response.SessionInfo;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
import shine.db.dao.ActiveSessionsDAO;
|
||||
import shine.db.entities.ActiveSessionEntry;
|
||||
@ -144,7 +143,7 @@ public class Net_ListSessions_Handler implements JsonMessageHandler {
|
||||
// 4) Собираем DTO с геолокацией
|
||||
List<SessionInfo> resultList = new ArrayList<>();
|
||||
for (ActiveSessionEntry s : sessions) {
|
||||
SessionInfo info = new SessionInfo();
|
||||
SessionInfo info = new Net_ListSessions_Response.SessionInfo();
|
||||
info.setSessionId(s.getSessionId());
|
||||
info.setClientInfoFromClient(s.getClientInfoFromClient());
|
||||
info.setClientInfoFromRequest(s.getClientInfoFromRequest());
|
||||
|
||||
@ -4,8 +4,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_RefreshSession_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.Auth.Net_RefreshSession_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.auth.entyties.*;
|
||||
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;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.Auth;
|
||||
package server.logic.ws_protocol.JSON.handlers.auth.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
@ -7,8 +7,10 @@ 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.entyties.blockchain.Net_AddBlock_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.blockchain.Net_AddBlock_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils.BlockchainLocks;
|
||||
import server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils.BlockchainWriter;
|
||||
import server.logic.ws_protocol.JSON.handlers.blockchain.entyties.Net_AddBlock_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.blockchain.entyties.Net_AddBlock_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
import shine.db.dao.BlockchainStateDAO;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.blockchain;
|
||||
package server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.handlers.blockchain;
|
||||
package server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils;
|
||||
|
||||
import blockchain.BchBlockEntry;
|
||||
import blockchain.body.ReactionBody;
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.blockchain;
|
||||
package server.logic.ws_protocol.JSON.handlers.blockchain.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.blockchain;
|
||||
package server.logic.ws_protocol.JSON.handlers.blockchain.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
@ -5,8 +5,8 @@ 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.entyties.tempToTest.Net_AddUser_Request;
|
||||
import server.logic.ws_protocol.JSON.entyties.tempToTest.Net_AddUser_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_AddUser_Request;
|
||||
import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_AddUser_Response;
|
||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.tempToTest;
|
||||
package server.logic.ws_protocol.JSON.handlers.tempToTest.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package server.logic.ws_protocol.JSON.entyties.tempToTest;
|
||||
package server.logic.ws_protocol.JSON.handlers.tempToTest.entyties;
|
||||
|
||||
import server.logic.ws_protocol.JSON.entyties.Net_Response;
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
*
|
||||
* | Смещение | Размер | Поле | Формат | Описание |
|
||||
* |-----------|--------|--------------------|---------|-----------|
|
||||
* | 0x00 | 8 | tag | ASCII | Статическая сигнатура "SHiNE001" |
|
||||
* | 0x00 | 8 | tag | ASCII | Статическая сигнатура "SHiNE" |
|
||||
*
|
||||
* | 0x10 | 1 | userLoginLength=N | uint8 | Длина логина пользователя |
|
||||
* | 0x11 | N | userLogin | UTF-8 | Логин пользователя |
|
||||
@ -34,7 +34,7 @@
|
||||
* ----------------------------------------------------------------------------
|
||||
* 💡 Пример структуры в байтах:
|
||||
*
|
||||
* 0000: 53 48 69 4E 45 30 30 31 "SHiNE001"
|
||||
* 0000: 53 48 69 4E 45 30 30 31 "SHiNE"
|
||||
* 0008: 00 00 00 00 01 23 45 67 blockchainId
|
||||
* 0010: 05 userLoginLength = 5
|
||||
* 0011: 41 69 64 61 72 userLogin = "Aidar"
|
||||
|
||||
@ -18,7 +18,7 @@ public final class InboundMessageProcessor {
|
||||
private static final Logger log = LoggerFactory.getLogger(InboundMessageProcessor.class);
|
||||
|
||||
private static final Map<Integer, MessageHandler> HANDLERS = Map.of(
|
||||
WireCodes.Op.PING, new PingHandler()
|
||||
// WireCodes.Op.PING, new PingHandler()
|
||||
// WireCodes.Op.ADD_BLOCK, new AddBlockHandler(),
|
||||
// WireCodes.Op.GET_BLOCKCHAIN,new GetBlockchainHandler()
|
||||
// WireCodes.Op.SEARCH_USERS, new SearchUsersHandler(),
|
||||
|
||||
@ -1,250 +0,0 @@
|
||||
//package server.logic.ws_protocol.binary.handlers;
|
||||
//
|
||||
//import blockchain.BchBlockEntry;
|
||||
//import blockchain.body.BodyRecord;
|
||||
//import blockchain.BodyRecordParser;
|
||||
//import blockchain.body.HeaderBody;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import server.logic.ws_protocol.WireCodes;
|
||||
//import utils.blockchain.BchInfoEntry;
|
||||
//import utils.blockchain.BchInfoManager;
|
||||
//import utils.crypto.BchCryptoVerifier;
|
||||
//import utils.files.FileStoreUtil;
|
||||
//
|
||||
//import java.nio.ByteBuffer;
|
||||
//import java.nio.ByteOrder;
|
||||
//import java.util.Arrays;
|
||||
//
|
||||
///**
|
||||
// * AddBlockHandler — обработчик команды "добавить блок" (ADD_BLOCK)
|
||||
// * ---------------------------------------------------------------
|
||||
// * Принимает бинарное сообщение от клиента и добавляет новый блок в цепочку.
|
||||
// *.
|
||||
// * Формат входного сообщения (msg):
|
||||
// * [0..3] — 4 байта: код операции (WireCodes.ADD_BLOCK)
|
||||
// * [4..11] — 8 байт: blockchainId (уникальный идентификатор цепочки)
|
||||
// * [12..] — байты полного блока .bch:
|
||||
// * ├── 4 байта recordSize = M + 18
|
||||
// * ├── 4 байта recordNumber
|
||||
// * ├── 8 байт timestamp
|
||||
// * ├── 2 байта recordType
|
||||
// * ├── 2 байта recordVersion
|
||||
// * ├── M байт body (содержимое блока)
|
||||
// * ├── 64 байта signature (Ed25519)
|
||||
// * └── 32 байта hash (SHA-256)
|
||||
// *.
|
||||
// * ---------------------------------------------------------------
|
||||
// * Алгоритм работы:
|
||||
// *.
|
||||
// * 1️⃣ Распаковать BchBlockEntry из msg (т.е. выделить тело блока и подписи).
|
||||
// * 2️⃣ Найти описание цепочки (BchInfoEntry) по blockchainId.
|
||||
// *.
|
||||
// * ─ Если описания нет (цепочка ещё не существует):
|
||||
// * • принимаем только блок типа 0 (HeaderBody) и номера 0;
|
||||
// * • парсим его, создаём новый BchInfoEntry на основе данных заголовка;
|
||||
// * • проверяем подпись и хэш;
|
||||
// * • проверяем корректность тела блока (check);
|
||||
// * • сохраняем блок и создаём новый blockchain-файл;
|
||||
// * • добавляем цепочку в менеджер BchInfoManager.
|
||||
// * (💡 временное решение: создание цепочки допустимо только через HeaderBody)
|
||||
// *.
|
||||
// * ─ Если цепочка уже существует:
|
||||
// * • проверяем, что номер блока равен (lastBlockNumber + 1);
|
||||
// * • проверяем подпись и хэш;
|
||||
// * • проверяем тело блока (check);
|
||||
// * • добавляем блок в файл цепочки;
|
||||
// * • обновляем состояние BchInfoEntry (номер, хэш, размер).
|
||||
// *.
|
||||
// * 3️⃣ Если все проверки пройдены — возвращаем статус OK.
|
||||
// *.
|
||||
// * Таким образом, единственное различие между первым блоком и последующими —
|
||||
// * момент инициализации описания цепочки (BchInfoEntry).
|
||||
// * Всё остальное (валидация, подпись, добавление, обновление) выполняется одинаково.
|
||||
// */
|
||||
//public class AddBlockHandler implements MessageHandler {
|
||||
//
|
||||
// private static final Logger log = LoggerFactory.getLogger(AddBlockHandler.class);
|
||||
//
|
||||
// @Override
|
||||
// public byte[] handle(byte[] msg) {
|
||||
// try {
|
||||
// // =====================================================================
|
||||
// // 1️⃣ Проверка минимальной длины пакета
|
||||
// // =====================================================================
|
||||
// int minFull = BchBlockEntry.RAW_HEADER_SIZE + BchBlockEntry.SIGNATURE_LEN + BchBlockEntry.HASH_LEN;
|
||||
// // (RAW_HEADER_SIZE = 18 байт, подпись = 64, хэш = 32)
|
||||
// if (msg.length < 4 + 8 + minFull)
|
||||
// return code(WireCodes.Status.BAD_REQUEST);
|
||||
//
|
||||
// // =====================================================================
|
||||
// // 2️⃣ Извлекаем blockchainId (8 байт начиная с позиции 4)
|
||||
// // =====================================================================
|
||||
// long blockchainId = ByteBuffer.wrap(msg, 4, 8)
|
||||
// .order(ByteOrder.BIG_ENDIAN)
|
||||
// .getLong();
|
||||
//
|
||||
// // Всё, что дальше, — это бинарное содержимое блока .bch
|
||||
// int offset = 12; // первые 12 байт = код + blockchainId
|
||||
//
|
||||
// // =====================================================================
|
||||
// // 3️⃣ Парсим блок (RAW + подпись + хэш)
|
||||
// // =====================================================================
|
||||
// byte[] fullBlock = Arrays.copyOfRange(msg, offset, msg.length);
|
||||
// BchBlockEntry block = new BchBlockEntry(fullBlock); // сам распакует RAW-часть и подписи
|
||||
//
|
||||
// // =====================================================================
|
||||
// // 4️⃣ Получаем текущее описание цепочки (BchInfoEntry)
|
||||
// // =====================================================================
|
||||
// BchInfoManager info = BchInfoManager.getInstance();
|
||||
// BchInfoEntry chain = info.getBchInfo(blockchainId);
|
||||
//
|
||||
// byte[] prevHash32;
|
||||
// int expectedNum;
|
||||
// String userLogin;
|
||||
// byte[] publicKey32;
|
||||
//
|
||||
// // =====================================================================
|
||||
// // 🧩 СЦЕНАРИЙ 1: цепочка отсутствует — создаём новую
|
||||
// // =====================================================================
|
||||
// if (chain == null) {
|
||||
// // Допускаем только блок-заголовок (type=0, num=0)
|
||||
// if (block.recordType != BchBlockEntry.TYPE_HEADER || block.recordNumber != 0) {
|
||||
// log.warn("Попытка создать новую цепочку без корректного заголовка (type={}, num={})",
|
||||
// block.recordType, block.recordNumber);
|
||||
// return code(WireCodes.Status.BAD_REQUEST);
|
||||
// }
|
||||
//
|
||||
// // Парсим тело блока → HeaderBody
|
||||
// BodyRecord body = BodyRecordParser.parse(block.recordType, block.recordTypeVersion, block.body).check();
|
||||
// if (!(body instanceof HeaderBody))
|
||||
// return code(WireCodes.Status.BAD_REQUEST);
|
||||
//
|
||||
// HeaderBody hb = (HeaderBody) body;
|
||||
//
|
||||
// // Проверяем, что blockchainId совпадает
|
||||
// if (hb.blockchainId != blockchainId) {
|
||||
// log.warn("Несовпадение blockchainId в заголовке (ожидалось {}, получено {})",
|
||||
// blockchainId, hb.blockchainId);
|
||||
// return code(WireCodes.Status.BAD_REQUEST);
|
||||
// }
|
||||
//
|
||||
// // Проверяем подпись и хэш первого блока (предыдущий хэш = 0)
|
||||
// prevHash32 = new byte[32];
|
||||
// boolean verified = BchCryptoVerifier.verifyAll(
|
||||
// hb.userLogin,
|
||||
// blockchainId,
|
||||
// prevHash32,
|
||||
// block.rawBytes,
|
||||
// block.getSignature64(),
|
||||
// block.getHash32(),
|
||||
// hb.publicKey32
|
||||
// );
|
||||
// if (!verified) {
|
||||
// log.warn("❌ Подпись не прошла проверку при создании цепочки blockchainId={}", blockchainId);
|
||||
// return code(WireCodes.Status.UNVERIFIED);
|
||||
// }
|
||||
//
|
||||
// // ✅ Всё хорошо: создаём новую цепочку
|
||||
// info.addBlockchain(blockchainId, hb.userLogin, hb.publicKey32, Integer.MAX_VALUE);
|
||||
// info.updateBlockchainState(blockchainId, block.recordNumber, bytesToHex(block.getHash32()), fullBlock.length);
|
||||
//
|
||||
// FileStoreUtil.getInstance().addDataToBlockchain(blockchainId, fullBlock);
|
||||
//
|
||||
// log.info("✅ Создана новая цепочка blockchainId={}, user={}, blockNum={}",
|
||||
// blockchainId, hb.userLogin, block.recordNumber);
|
||||
//
|
||||
// return code(WireCodes.Status.OK);
|
||||
// }
|
||||
//
|
||||
// // =====================================================================
|
||||
// // 🧩 СЦЕНАРИЙ 2: цепочка существует — добавляем новый блок
|
||||
// // =====================================================================
|
||||
// expectedNum = chain.lastBlockNumber + 1;
|
||||
//
|
||||
// // Проверка последовательности (и отправка lastBlockNumber)
|
||||
// if (block.recordNumber < expectedNum) {
|
||||
// log.info("🔁 Блок {} уже существует, последний = {}", block.recordNumber, chain.lastBlockNumber);
|
||||
// ByteBuffer out = ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN);
|
||||
// out.putInt(WireCodes.Status.BLOCK_ALREADY_EXISTS);
|
||||
// out.putInt(chain.lastBlockNumber);
|
||||
// return out.array();
|
||||
// }
|
||||
// if (block.recordNumber > expectedNum) {
|
||||
// log.warn("⚠️ Нарушена последовательность: получен {}, ожидался {}", block.recordNumber, expectedNum);
|
||||
// ByteBuffer out = ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN);
|
||||
// out.putInt(WireCodes.Status.OUT_OF_SEQUENCE);
|
||||
// out.putInt(chain.lastBlockNumber);
|
||||
// return out.array();
|
||||
// }
|
||||
//
|
||||
// userLogin = chain.userLogin;
|
||||
// publicKey32 = chain.getPublicKey32();
|
||||
//
|
||||
// // Хэш предыдущего блока (или 32 нуля, если это первый)
|
||||
// prevHash32 = (chain.lastBlockHash == null || chain.lastBlockHash.isEmpty())
|
||||
// ? new byte[32]
|
||||
// : hexToBytes(chain.lastBlockHash);
|
||||
//
|
||||
// // Проверяем подпись и хэш
|
||||
// boolean verified = BchCryptoVerifier.verifyAll(
|
||||
// userLogin,
|
||||
// blockchainId,
|
||||
// prevHash32,
|
||||
// block.rawBytes,
|
||||
// block.getSignature64(),
|
||||
// block.getHash32(),
|
||||
// publicKey32
|
||||
// );
|
||||
// if (!verified) {
|
||||
// log.warn("❌ Подпись не прошла проверку: chainId={}, blockNum={}", blockchainId, block.recordNumber);
|
||||
// return code(WireCodes.Status.UNVERIFIED);
|
||||
// }
|
||||
//
|
||||
// // Проверяем тело блока (например, корректный UTF-8 или структура)
|
||||
// BodyRecord body = BodyRecordParser.parse(block.recordType, block.recordTypeVersion, block.body).check();
|
||||
//
|
||||
// // ✅ Добавляем блок в файл цепочки
|
||||
// FileStoreUtil.getInstance().addDataToBlockchain(blockchainId, fullBlock);
|
||||
//
|
||||
// // Обновляем состояние цепочки (номер, хэш, размер)
|
||||
// int newSize = chain.blockchainSize + fullBlock.length;
|
||||
// info.updateBlockchainState(blockchainId, block.recordNumber, bytesToHex(block.getHash32()), newSize);
|
||||
//
|
||||
// log.info("✅ Блок добавлен: chain={}, num={}, type={}, bytes={}",
|
||||
// blockchainId, block.recordNumber, block.recordType, fullBlock.length);
|
||||
//
|
||||
// return code(WireCodes.Status.OK);
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// log.error("❌ ADD_BLOCK: внутренняя ошибка при обработке", e);
|
||||
// return code(WireCodes.Status.INTERNAL_ERROR);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // =====================================================================
|
||||
// // Утилиты
|
||||
// // =====================================================================
|
||||
//
|
||||
// /** Преобразовать статус (int) в 4 байта BigEndian. */
|
||||
// private static byte[] code(int status) {
|
||||
// return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(status).array();
|
||||
// }
|
||||
//
|
||||
// /** Конвертация HEX → bytes (для хэшей). */
|
||||
// private static byte[] hexToBytes(String hex) {
|
||||
// int len = hex.length();
|
||||
// byte[] out = new byte[len / 2];
|
||||
// for (int i = 0; i < len; i += 2)
|
||||
// out[i / 2] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
|
||||
// return out;
|
||||
// }
|
||||
//
|
||||
// /** Конвертация bytes → HEX (для сохранения в BchInfo). */
|
||||
// private static String bytesToHex(byte[] b) {
|
||||
// StringBuilder sb = new StringBuilder(b.length * 2);
|
||||
// for (byte x : b) sb.append(String.format("%02x", x));
|
||||
// return sb.toString();
|
||||
// }
|
||||
//}
|
||||
//
|
||||
@ -1,53 +0,0 @@
|
||||
//package server.logic.ws_protocol.binary.handlers;
|
||||
//
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import server.logic.ws_protocol.WireCodes;
|
||||
//import utils.files.FileStoreUtil;
|
||||
//
|
||||
//import java.nio.ByteBuffer;
|
||||
//import java.nio.ByteOrder;
|
||||
//
|
||||
///**
|
||||
// * Возврат полного содержимого блокчейна (GET_BLOCKCHAIN).
|
||||
// */
|
||||
//public class GetBlockchainHandler implements MessageHandler {
|
||||
// private static final Logger log = LoggerFactory.getLogger(GetBlockchainHandler.class);
|
||||
//
|
||||
// @Override
|
||||
// public byte[] handle(byte[] msg) {
|
||||
// try {
|
||||
// if (msg.length < 12)
|
||||
// return intTo4Bytes(WireCodes.Status.BAD_REQUEST);
|
||||
//
|
||||
// long id = ByteBuffer.wrap(msg, 4, 8)
|
||||
// .order(ByteOrder.BIG_ENDIAN)
|
||||
// .getLong();
|
||||
//
|
||||
// FileStoreUtil fs = FileStoreUtil.getInstance();
|
||||
// byte[] data = fs.readAllDataFromBlockchain(id);
|
||||
//
|
||||
// return packOk(data);
|
||||
//
|
||||
// } catch (IllegalStateException e) {
|
||||
// log.warn("GET_BLOCKCHAIN: файл не найден ({})", e.getMessage());
|
||||
// return intTo4Bytes(WireCodes.Status.CHAIN_NOT_FOUND);
|
||||
// } catch (Exception e) {
|
||||
// log.error("GET_BLOCKCHAIN: ошибка", e);
|
||||
// return intTo4Bytes(WireCodes.Status.INTERNAL_ERROR);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static byte[] packOk(byte[] data) {
|
||||
// if (data == null) data = new byte[0];
|
||||
// ByteBuffer out = ByteBuffer.allocate(8 + data.length).order(ByteOrder.BIG_ENDIAN);
|
||||
// out.putInt(WireCodes.Status.OK);
|
||||
// out.putInt(data.length);
|
||||
// out.put(data);
|
||||
// return out.array();
|
||||
// }
|
||||
//
|
||||
// private static byte[] intTo4Bytes(int code) {
|
||||
// return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(code).array();
|
||||
// }
|
||||
//}
|
||||
@ -1,66 +0,0 @@
|
||||
//package server.logic.ws_protocol.binary.handlers;
|
||||
//
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import server.logic.ws_protocol.WireCodes;
|
||||
//import utils.blockchain.BchInfoEntry;
|
||||
//import utils.blockchain.BchInfoManager;
|
||||
//
|
||||
//import java.nio.ByteBuffer;
|
||||
//import java.nio.ByteOrder;
|
||||
//import java.util.Arrays;
|
||||
//
|
||||
///**
|
||||
// * Возврат информации о последнем блоке цепочки (GET_LAST_BLOCK_INFO).
|
||||
// */
|
||||
//public class GetLastBlockInfoHandler implements MessageHandler {
|
||||
// private static final Logger log = LoggerFactory.getLogger(GetLastBlockInfoHandler.class);
|
||||
//
|
||||
// @Override
|
||||
// public byte[] handle(byte[] msg) {
|
||||
// try {
|
||||
// if (msg.length < 12)
|
||||
// return intTo4Bytes(WireCodes.Status.BAD_REQUEST);
|
||||
//
|
||||
// long blockchainId = ByteBuffer.wrap(msg, 4, 8)
|
||||
// .order(ByteOrder.BIG_ENDIAN)
|
||||
// .getLong();
|
||||
//
|
||||
// BchInfoManager mgr = BchInfoManager.getInstance();
|
||||
// BchInfoEntry entry = mgr.getBchInfo(blockchainId);
|
||||
// if (entry == null)
|
||||
// return intTo4Bytes(WireCodes.Status.CHAIN_NOT_FOUND);
|
||||
//
|
||||
// int lastNum = entry.lastBlockNumber;
|
||||
// byte[] hash = hexToBytes(entry.lastBlockHash);
|
||||
//
|
||||
// ByteBuffer out = ByteBuffer.allocate(4 + 4 + 32).order(ByteOrder.BIG_ENDIAN);
|
||||
// out.putInt(WireCodes.Status.OK);
|
||||
// out.putInt(lastNum);
|
||||
// out.put(hash);
|
||||
// return out.array();
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// log.error("GET_LAST_BLOCK_INFO: ошибка", e);
|
||||
// return intTo4Bytes(WireCodes.Status.INTERNAL_ERROR);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static byte[] intTo4Bytes(int code) {
|
||||
// return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(code).array();
|
||||
// }
|
||||
//
|
||||
// private static byte[] hexToBytes(String hex) {
|
||||
// if (hex == null || hex.isEmpty()) return new byte[32];
|
||||
// int len = hex.length();
|
||||
// byte[] out = new byte[len / 2];
|
||||
// for (int i = 0; i < len; i += 2)
|
||||
// out[i / 2] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
|
||||
// if (out.length < 32) { // добиваем нулями
|
||||
// byte[] full = new byte[32];
|
||||
// System.arraycopy(out, 0, full, 32 - out.length, out.length);
|
||||
// return full;
|
||||
// }
|
||||
// return Arrays.copyOf(out, 32);
|
||||
// }
|
||||
//}
|
||||
@ -1,16 +0,0 @@
|
||||
package server.logic.ws_protocol.binary.handlers;
|
||||
|
||||
import server.logic.ws_protocol.WireCodes;
|
||||
|
||||
/**
|
||||
* Обработчик команды PING.
|
||||
* Возвращает просто статус PONG.
|
||||
*/
|
||||
public class PingHandler implements MessageHandler {
|
||||
@Override
|
||||
public byte[] handle(byte[] msg) {
|
||||
return new byte[]{
|
||||
0, 0, 0, (byte) WireCodes.Status.PONG // проще и быстрее, можно и через ByteBuffer
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
//package server.logic.ws_protocol.binary.handlers;
|
||||
//
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import server.logic.ws_protocol.WireCodes;
|
||||
//import utils.search.UserSearchService;
|
||||
//
|
||||
//import java.nio.ByteBuffer;
|
||||
//import java.nio.ByteOrder;
|
||||
//import java.nio.charset.StandardCharsets;
|
||||
//import java.util.List;
|
||||
//
|
||||
///**
|
||||
// * Поиск пользователей по логину (SEARCH_USERS).
|
||||
// */
|
||||
//public class SearchUsersHandler implements MessageHandler {
|
||||
// private static final Logger log = LoggerFactory.getLogger(SearchUsersHandler.class);
|
||||
//
|
||||
// @Override
|
||||
// public byte[] handle(byte[] msg) {
|
||||
// try {
|
||||
// if (msg.length < 8)
|
||||
// return intTo4Bytes(WireCodes.Status.BAD_REQUEST);
|
||||
//
|
||||
// int N = ByteBuffer.wrap(msg, 4, 4).order(ByteOrder.BIG_ENDIAN).getInt();
|
||||
// if (N < 0 || msg.length < 8 + N)
|
||||
// return intTo4Bytes(WireCodes.Status.BAD_REQUEST);
|
||||
//
|
||||
// String query = new String(msg, 8, N, StandardCharsets.UTF_8);
|
||||
// List<UserSearchService.Pair> found = UserSearchService.getInstance().searchFirst5(query);
|
||||
// return pack(found);
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// log.error("SEARCH_USERS: ошибка", e);
|
||||
// return intTo4Bytes(WireCodes.Status.INTERNAL_ERROR);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static byte[] pack(List<UserSearchService.Pair> pairs) {
|
||||
// if (pairs == null) pairs = List.of();
|
||||
// int total = 8;
|
||||
// var chunks = new java.util.ArrayList<byte[]>();
|
||||
// for (var p : pairs) {
|
||||
// byte[] packed = UserSearchService.packPair(p);
|
||||
// chunks.add(packed);
|
||||
// total += packed.length;
|
||||
// }
|
||||
//
|
||||
// ByteBuffer out = ByteBuffer.allocate(total).order(ByteOrder.BIG_ENDIAN);
|
||||
// out.putInt(WireCodes.Status.OK);
|
||||
// out.putInt(pairs.size());
|
||||
// for (var c : chunks) out.put(c);
|
||||
// return out.array();
|
||||
// }
|
||||
//
|
||||
// private static byte[] intTo4Bytes(int code) {
|
||||
// return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(code).array();
|
||||
// }
|
||||
//}
|
||||
@ -1,5 +1,3 @@
|
||||
server.1port=7070
|
||||
|
||||
|
||||
db.path=data/shine.sqlite
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
public static void main(String[] args) {
|
||||
int failed = run();
|
||||
System.exit(failed);
|
||||
// System.exit(failed);
|
||||
}
|
||||
|
||||
/** Запуск одного теста (standalone). Возвращает 0 если ок, 1 если упал. */
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
|
||||
// === Построение HEADER ===
|
||||
function buildHeaderBody() {
|
||||
const tag = textUtf8("SHiNE001");
|
||||
const tag = textUtf8("SHiNE");
|
||||
const id = beLong(blockchainId);
|
||||
const login = textUtf8(userLogin);
|
||||
const loginLen = new Uint8Array([login.length]);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user