diff --git a/shine-server-blockchain/src/main/java/utils/files/FileStoreUtil.java b/shine-server-blockchain/src/main/java/utils/files/FileStoreUtil.java index 51ebb71..9872c88 100644 --- a/shine-server-blockchain/src/main/java/utils/files/FileStoreUtil.java +++ b/shine-server-blockchain/src/main/java/utils/files/FileStoreUtil.java @@ -6,40 +6,29 @@ import java.util.Objects; /** * =============================================================== - * FileStoreUtil — синглтон-утилита для записи/дозаписи/чтения файлов. - * --------------------------------------------------------------- - * Где хранит: - * • Все файлы размещаются в внешней папке DATA_DIR = "data" (в корне запуска). - * Папка создаётся автоматически при первом обращении. - *. - * Что умеет: - * • newFile(String fileName, byte[] data) - * - создаёт/переписывает файл с именем fileName и записывает data. - * • addDataToFile(String fileName, byte[] data) - * - дописывает data в конец файла (создаст файл, если его ещё нет). - * • readAllDataFromFile(String fileName) - * - читает весь файл целиком и возвращает содержимое в виде byte[]. - *. - * Обёртки под «блокчейны»: - * • newBlockchain(long blockchainId, byte[] data) - * • addDataToBlockchain(long blockchainId, byte[] data) - * • readAllDataFromBlockchain(long blockchainId) - * - те же операции, но имя файла формируется из blockchainId и расширения ".bch". - *. - * Безопасность имён: - * • Внутри утилиты есть простая валидация имени файла: запрещены разделители путей, - * чтобы исключить выход из каталога data (path traversal). - *. - * Совместимость: Java 17. + * FileStoreUtil — утилита работы с файлами в папке data/. + * + * Теперь поддерживает: + * - основной файл блокчейна: .bch + * - временный файл блокчейна: .tmp_bch + * + * Важное: + * - validateSimpleFileName() запрещает path traversal. + * - atomicReplaceBlockchainFile(): пытается сделать ATOMIC_MOVE (если ФС поддерживает), + * иначе делает обычный REPLACE_EXISTING move. * =============================================================== */ public final class FileStoreUtil { /** Базовая папка для хранения всех файлов (создаётся автоматически). */ public static final String DATA_DIR_NAME = "data"; - /** Расширение файлов «блокчейнов». */ + + /** Расширение основного файла блокчейна. */ public static final String BLOCKCHAIN_FILE_EXTENSION = ".bch"; + /** Расширение временного файла (старое+новое). */ + public static final String BLOCKCHAIN_TMP_EXTENSION = ".tmp_bch"; + private static final FileStoreUtil INSTANCE = new FileStoreUtil(); private final Path dataDirPath; @@ -49,56 +38,40 @@ public final class FileStoreUtil { ensureDataDirExists(); } - /** Получить единственный экземпляр утилиты. */ public static FileStoreUtil getInstance() { return INSTANCE; } - // =============================================================== - // ОБЩИЕ МЕТОДЫ РАБОТЫ С ФАЙЛОМ - // =============================================================== + /* ===================================================================== */ + /* ======================== Базовые операции =========================== */ + /* ===================================================================== */ - /** - * Создать/переписать файл и записать в него массив байт. - * @param fileName имя файла (без каталогов) - * @param data содержимое - * @throws IllegalArgumentException при неверном имени или null-данных - * @throws IllegalStateException при ошибках ввода/вывода - */ public void newFile(String fileName, byte[] data) { - Objects.requireNonNull(data, "Данные не должны быть null"); + Objects.requireNonNull(data, "data == null"); Path target = resolveSafe(fileName); try { - Files.write(target, data, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); + Files.write(target, data, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.WRITE); } catch (IOException e) { throw new IllegalStateException("Не удалось записать файл: " + target, e); } } - /** - * Дозаписать массив байт в конец файла (создаст файл, если отсутствует). - * @param fileName имя файла (без каталогов) - * @param data добавляемые данные - * @throws IllegalArgumentException при неверном имени или null-данных - * @throws IllegalStateException при ошибках ввода/вывода - */ public void addDataToFile(String fileName, byte[] data) { - Objects.requireNonNull(data, "Данные не должны быть null"); + Objects.requireNonNull(data, "data == null"); Path target = resolveSafe(fileName); try { Files.write(target, data, - StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.APPEND); + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.APPEND); } catch (IOException e) { throw new IllegalStateException("Не удалось дописать файл: " + target, e); } } - /** - * Прочитать весь файл в память и вернуть как byte[]. - * @param fileName имя файла (без каталогов) - * @return содержимое файла - * @throws IllegalStateException если файл не существует или ошибка ввода/вывода - */ public byte[] readAllDataFromFile(String fileName) { Path target = resolveSafe(fileName); if (!Files.exists(target)) { @@ -111,37 +84,91 @@ public final class FileStoreUtil { } } - // =============================================================== - // ОБЁРТКИ ДЛЯ «БЛОКЧЕЙН-ФАЙЛОВ» - // =============================================================== + public boolean exists(String fileName) { + Path target = resolveSafe(fileName); + return Files.exists(target); + } - /** - * Обёртка над newFile: имя формируется из blockchainId + ".bch". - */ - public void newBlockchain(long blockchainId, byte[] data) { - String fileName = buildBlockchainFileName(blockchainId); - newFile(fileName, data); + public long size(String fileName) { + Path target = resolveSafe(fileName); + try { + return Files.size(target); + } catch (IOException e) { + throw new IllegalStateException("Не удалось получить размер файла: " + target, e); + } + } + + /* ===================================================================== */ + /* ===================== Блокчейн-файлы по имени ======================= */ + /* ===================================================================== */ + + /** .bch */ + public String buildBlockchainFileName(String blockchainName) { + validateSimpleFileName(blockchainName); + return blockchainName + BLOCKCHAIN_FILE_EXTENSION; + } + + /** .tmp_bch */ + public String buildBlockchainTmpFileName(String blockchainName) { + validateSimpleFileName(blockchainName); + return blockchainName + BLOCKCHAIN_TMP_EXTENSION; + } + + public Path resolveBlockchainPath(String blockchainName) { + return resolveSafe(buildBlockchainFileName(blockchainName)); + } + + public Path resolveBlockchainTmpPath(String blockchainName) { + return resolveSafe(buildBlockchainTmpFileName(blockchainName)); + } + + public byte[] readBlockchain(String blockchainName) { + return readAllDataFromFile(buildBlockchainFileName(blockchainName)); + } + + public void writeBlockchainTmp(String blockchainName, byte[] data) { + newFile(buildBlockchainTmpFileName(blockchainName), data); } /** - * Обёртка над addDataToFile: имя формируется из blockchainId + ".bch". + * Атомарно заменить основной файл блокчейна временным: + * .tmp_bch -> .bch + * + * Стратегия: + * 1) Пытаемся Files.move(..., ATOMIC_MOVE, REPLACE_EXISTING) + * 2) Если ATOMIC_MOVE не поддерживается — делаем move с REPLACE_EXISTING без атомарности + * + * Важный нюанс: + * - атомарность гарантируется только в пределах одной файловой системы. */ - public void addDataToBlockchain(long blockchainId, byte[] data) { - String fileName = buildBlockchainFileName(blockchainId); - addDataToFile(fileName, data); + public void atomicReplaceBlockchainFile(String blockchainName) { + Path tmp = resolveBlockchainTmpPath(blockchainName); + Path main = resolveBlockchainPath(blockchainName); + + if (!Files.exists(tmp)) { + throw new IllegalStateException("TMP-файл не найден: " + tmp); + } + + try { + // 1) Пытаемся атомарный move + Files.move(tmp, main, + StandardCopyOption.REPLACE_EXISTING, + StandardCopyOption.ATOMIC_MOVE); + } catch (AtomicMoveNotSupportedException e) { + // 2) Если ФС не поддерживает атомарный move — делаем обычный replace + try { + Files.move(tmp, main, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException ex) { + throw new IllegalStateException("Не удалось заменить файл блокчейна (non-atomic): " + main, ex); + } + } catch (IOException e) { + throw new IllegalStateException("Не удалось заменить файл блокчейна (atomic): " + main, e); + } } - /** - * Обёртка над readAllDataFromFile: имя формируется из blockchainId + ".bch". - */ - public byte[] readAllDataFromBlockchain(long blockchainId) { - String fileName = buildBlockchainFileName(blockchainId); - return readAllDataFromFile(fileName); - } - - // =============================================================== - // ВСПОМОГАТЕЛЬНЫЕ - // =============================================================== + /* ===================================================================== */ + /* ============================ Helpers ================================= */ + /* ===================================================================== */ private void ensureDataDirExists() { try { @@ -153,20 +180,21 @@ public final class FileStoreUtil { } } - /** - * Безопасно собрать путь внутри каталога data, запретив подстановку каталогов в имени файла. - */ private Path resolveSafe(String fileName) { validateSimpleFileName(fileName); return dataDirPath.resolve(fileName); } /** - * Простейшая валидация имени файла: - * • запретить разделители путей и возврат на родительский каталог. + * Валидация "простого имени": + * - запрещаем слэши, обратные слэши, ".." + * - запрещаем пустоту + * + * Важно: сюда у нас попадает и blockchainName (как часть имени файла), + * поэтому blockchainName должен быть "простым": без путей. */ private void validateSimpleFileName(String fileName) { - Objects.requireNonNull(fileName, "Имя файла не должно быть null"); + Objects.requireNonNull(fileName, "fileName == null"); if (fileName.isBlank()) { throw new IllegalArgumentException("Имя файла не должно быть пустым"); } @@ -174,12 +202,4 @@ public final class FileStoreUtil { throw new IllegalArgumentException("Недопустимое имя файла: " + fileName); } } - - /** - * Построить имя «блокчейн-файла» из идентификатора и расширения .bch. - * Пример: 12345 → "12345.bch" - */ - private String buildBlockchainFileName(long blockchainId) { - return Long.toString(blockchainId) + BLOCKCHAIN_FILE_EXTENSION; - } -} +} \ No newline at end of file diff --git a/shine-server-blockchain/src/main/java/utils/files/FileStoreUtilSelfTest.java b/shine-server-blockchain/src/main/java/utils/files/FileStoreUtilSelfTest.java index 928acf9..6dd0127 100644 --- a/shine-server-blockchain/src/main/java/utils/files/FileStoreUtilSelfTest.java +++ b/shine-server-blockchain/src/main/java/utils/files/FileStoreUtilSelfTest.java @@ -1,59 +1,59 @@ -package utils.files; - -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -/** - * =============================================================== - * FileStoreUtilSelfTest — запускаемый тест утилиты FileStoreUtil. - * --------------------------------------------------------------- - * Сценарий: - * 1) Создаём «блокчейн-файл» для id=20251021 с начальными данными. - * 2) Дозаписываем ещё порцию данных. - * 3) Читаем целиком и печатаем длину + превью. - *. - * Ожидаемый итог: - * • В папке "data" появится файл "20251021.bch" - * • В консоли будет длина содержимого и небольшой превью-дамп. - * =============================================================== - */ -public class FileStoreUtilSelfTest { - - public static void main(String[] args) { - System.out.println("=== FileStoreUtil self-test ==="); - - FileStoreUtil fs = FileStoreUtil.getInstance(); - - long blockchainId = 20251021L; - - byte[] part1 = "Hello ".getBytes(StandardCharsets.UTF_8); - byte[] part2 = "Blockchain!".getBytes(StandardCharsets.UTF_8); - - // 1) создаём новый файл для «блокчейна» - fs.newBlockchain(blockchainId, part1); - - // 2) дозаписываем данные - fs.addDataToBlockchain(blockchainId, part2); - - // 3) читаем всё содержимое и показываем превью - byte[] all = fs.readAllDataFromBlockchain(blockchainId); - System.out.println("Total bytes read: " + all.length); - System.out.println("Preview (UTF-8): " + new String(all, StandardCharsets.UTF_8)); - - // небольшой hex-дамп первых 32 байт (для наглядности) - System.out.println("Preview (HEX 32B): " + toHexPreview(all, 32)); - - System.out.println("✅ Self-test passed (файл: data/" + blockchainId + FileStoreUtil.BLOCKCHAIN_FILE_EXTENSION + ")"); - } - - private static String toHexPreview(byte[] data, int max) { - int n = Math.min(data.length, max); - StringBuilder sb = new StringBuilder(n * 2); - for (int i = 0; i < n; i++) { - sb.append(String.format("%02X", data[i])); - if (i + 1 < n) sb.append(' '); - } - if (data.length > n) sb.append(" ..."); - return sb.toString(); - } -} +//package utils.files; +// +//import java.nio.charset.StandardCharsets; +//import java.util.Arrays; +// +///** +// * =============================================================== +// * FileStoreUtilSelfTest — запускаемый тест утилиты FileStoreUtil. +// * --------------------------------------------------------------- +// * Сценарий: +// * 1) Создаём «блокчейн-файл» для id=20251021 с начальными данными. +// * 2) Дозаписываем ещё порцию данных. +// * 3) Читаем целиком и печатаем длину + превью. +// *. +// * Ожидаемый итог: +// * • В папке "data" появится файл "20251021.bch" +// * • В консоли будет длина содержимого и небольшой превью-дамп. +// * =============================================================== +// */ +//public class FileStoreUtilSelfTest { +// +// public static void main(String[] args) { +// System.out.println("=== FileStoreUtil self-test ==="); +// +// FileStoreUtil fs = FileStoreUtil.getInstance(); +// +// long blockchainId = 20251021L; +// +// byte[] part1 = "Hello ".getBytes(StandardCharsets.UTF_8); +// byte[] part2 = "Blockchain!".getBytes(StandardCharsets.UTF_8); +// +// // 1) создаём новый файл для «блокчейна» +// fs.newBlockchain(blockchainId, part1); +// +// // 2) дозаписываем данные +// fs.addDataToBlockchain(blockchainId, part2); +// +// // 3) читаем всё содержимое и показываем превью +// byte[] all = fs.readAllDataFromBlockchain(blockchainId); +// System.out.println("Total bytes read: " + all.length); +// System.out.println("Preview (UTF-8): " + new String(all, StandardCharsets.UTF_8)); +// +// // небольшой hex-дамп первых 32 байт (для наглядности) +// System.out.println("Preview (HEX 32B): " + toHexPreview(all, 32)); +// +// System.out.println("✅ Self-test passed (файл: data/" + blockchainId + FileStoreUtil.BLOCKCHAIN_FILE_EXTENSION + ")"); +// } +// +// private static String toHexPreview(byte[] data, int max) { +// int n = Math.min(data.length, max); +// StringBuilder sb = new StringBuilder(n * 2); +// for (int i = 0; i < n; i++) { +// sb.append(String.format("%02X", data[i])); +// if (i + 1 < n) sb.append(' '); +// } +// if (data.length > n) sb.append(" ..."); +// return sb.toString(); +// } +//} diff --git a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/BlockchainWriter.java b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/BlockchainWriter.java index b97ca0b..f7ba3ca 100644 --- a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/BlockchainWriter.java +++ b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/BlockchainWriter.java @@ -6,29 +6,46 @@ import shine.db.dao.BlockchainStateDAO; import shine.db.dao.BlocksDAO; import shine.db.entities.BlockEntry; import shine.db.entities.BlockchainStateEntry; +import utils.files.FileStoreUtil; import java.sql.Connection; import java.sql.SQLException; /** - * BlockchainDbWriter — единая точка записи блока + состояния в БД. + * BlockchainWriter — единая точка записи: + * 1) создаём новый файл .tmp_bch = oldFileBytes + newBlockBytes + * 2) атомарно фиксируем в БД: + * - blocks (строка блока) + * - blockchain_state (включая новый fileSizeBytes) + * 3) атомарно заменяем файл: + * - удаляем/замещаем старый .bch + * - переименовываем .tmp_bch -> .bch * * Важно: - * - Здесь обеспечивается атомарность записи: либо вставился блок и обновилось состояние, либо не вставилось ничего. - * - Соединение открывается/закрывается внутри (удобно для хэндлера). + * - Шаг (2) — строго атомарный (SQL tx). + * - Шаг (3) — атомарный на уровне ФС, если поддерживается ATOMIC_MOVE. + * - Если сервер упадёт между (2) и (3), останется tmp — твой recovery при старте починит. */ public final class BlockchainWriter { private final SqliteDbController db; private final BlocksDAO blocksDAO; private final BlockchainStateDAO stateDAO; + private final FileStoreUtil fs; public BlockchainWriter(BlocksDAO blocksDAO, BlockchainStateDAO stateDAO) { this.db = SqliteDbController.getInstance(); this.blocksDAO = blocksDAO; this.stateDAO = stateDAO; + this.fs = FileStoreUtil.getInstance(); } + /** + * Главный метод: + * - создаёт tmp-файл (старое+новое), + * - атомарно коммитит БД (block+state), + * - атомарно заменяет основной файл. + */ public void appendBlockAndState( String login, String blockchainName, @@ -38,43 +55,126 @@ public final class BlockchainWriter { String newHashHex ) throws SQLException { + // ===================================================================== + // ШАГ 1. Готовим bytes нового блока (включая signature+hash) + // ===================================================================== + final byte[] newBlockFullBytes = block.toBytes(); // ✅ включает хвост signature+hash + + // ===================================================================== + // ШАГ 2. Считаем новый fileSizeBytes + // - если genesis (state == null): старый размер = 0 + // - иначе берём st.fileSizeBytes + // ===================================================================== + final long oldFileSize = (stOrNull == null) ? 0L : stOrNull.getFileSizeBytes(); + final long newFileSize = safeAdd(oldFileSize, newBlockFullBytes.length); + + // ===================================================================== + // ШАГ 3. Создаём новый tmp-файл: + // tmp = (old file bytes) + (new block bytes) + // + // Важно: + // - читаем старый файл ТОЛЬКО если state не null и size > 0 + // - если genesis: старого файла нет => tmp = newBlock + // ===================================================================== + final byte[] tmpBytes; + if (stOrNull == null || oldFileSize == 0) { + // genesis: tmp = только новый блок + tmpBytes = newBlockFullBytes; + } else { + // не genesis: tmp = старый файл + новый блок + byte[] oldBytes; + try { + oldBytes = fs.readBlockchain(blockchainName); + } catch (Exception e) { + // Здесь лучше падать: state говорит, что файл есть, а прочитать нельзя. + throw new SQLException("Cannot read old blockchain file for: " + blockchainName, e); + } + + // (на будущее) можно проверять согласованность: oldBytes.length == oldFileSize + // но ты всё равно будешь делать recovery при старте — оставим как подсказку. + + tmpBytes = concat(oldBytes, newBlockFullBytes); + } + + // Пишем tmp на диск ДО транзакции БД: + // - если сервер упадёт позже — tmp останется, но БД может не успеть обновиться (это ок для recovery) + try { + fs.writeBlockchainTmp(blockchainName, tmpBytes); + } catch (Exception e) { + throw new SQLException("Cannot write tmp blockchain file for: " + blockchainName, e); + } + + // ===================================================================== + // ШАГ 4. АТОМАРНО фиксируем БД: + // - UPSERT blocks + // - UPSERT blockchain_state (включая fileSizeBytes = newFileSize) + // ===================================================================== try (Connection c = db.getConnection()) { boolean oldAutoCommit = c.getAutoCommit(); c.setAutoCommit(false); + boolean committed = false; + try { - // 1) блок + // 4.1) вставляем/апдейтим запись блока insertBlockRow(c, login, blockchainName, prevGlobalHashHex, block); - // 2) state - appendState(c, blockchainName, block.recordNumber, stOrNull, newHashHex); + // 4.2) апдейтим состояние (включая fileSizeBytes) + appendState(c, blockchainName, block.recordNumber, stOrNull, newHashHex, newFileSize); - // 3) commit + // 4.3) commit c.commit(); + committed = true; } catch (Exception e) { try { c.rollback(); } catch (SQLException ignore) {} if (e instanceof SQLException se) throw se; - throw new SQLException("appendBlockAndState failed", e); + throw new SQLException("appendBlockAndState failed (db tx)", e); } finally { try { c.setAutoCommit(oldAutoCommit); } catch (SQLException ignore) {} } + + // ================================================================= + // ШАГ 5. После успешного коммита БД — атомарно заменяем файл: + // .tmp_bch -> .bch + // + // Если тут упадём: + // - БД уже обновлена + // - tmp остаётся + // - recovery при старте восстановит консистентность + // ================================================================= + if (committed) { + try { + fs.atomicReplaceBlockchainFile(blockchainName); + } catch (Exception moveError) { + // Здесь ВАЖНО: мы уже не можем откатить БД. + // Оставляем tmp и даём наверх ошибку — клиент увидит internal_error, + // а ты при старте починишь файловую часть. + throw new SQLException( + "DB committed but file replace failed; tmp kept for recovery. blockchainName=" + blockchainName, + moveError + ); + } + } } } /** * Обновление состояния blockchain_state (создаём если отсутствует). * Пока линии не используются: lineIndex=0 и lineHash = globalHash. + * + * + обновляем fileSizeBytes */ private void appendState( Connection c, String blockchainName, int globalNumber, BlockchainStateEntry stOrNull, - String newHashHex + String newHashHex, + long newFileSizeBytes ) throws SQLException { BlockchainStateEntry st = stOrNull; @@ -87,14 +187,17 @@ public final class BlockchainWriter { st.setLastGlobalNumber(globalNumber); st.setLastGlobalHash(newHashHex); - // Линии пока не используются: lineIndex=0 и lineHash=globalHash + // Линии пока не используются st.setLastLineNumber(0, globalNumber); st.setLastLineHash(0, newHashHex); + // ✅ ВАЖНО: сохраняем ожидаемый размер файла + st.setFileSizeBytes(newFileSizeBytes); + // Метка времени обновления st.setUpdatedAtMs(System.currentTimeMillis()); - // UPSERT состояния + // UPSERT stateDAO.upsert(c, st); } @@ -111,33 +214,48 @@ public final class BlockchainWriter { BlockEntry e = new BlockEntry(); - // Кому принадлежит блок (логин владельца цепочки) e.setLogin(login); e.setBchName(blockchainName); - // Глобальная нумерация e.setBlockGlobalNumber(block.recordNumber); e.setBlockGlobalPreHashe(prevGlobalHashHex); - // Линии пока не используются: lineIndex=0, lineNumber=globalNumber + // линии пока не используем e.setBlockLineIndex(0); e.setBlockLineNumber(block.recordNumber); e.setBlockLinePreHashe(prevGlobalHashHex); - // msgType у тебя пока 0 (при желании позже можно ставить по Body/type) - // ✅ Теперь сохраняем тип блока + // тип сообщения — по body.type() e.setMsgType(block.body.type()); - // Сырые байты полного блока + // полный блок (RAW + signature + hash) e.setBlockByte(block.toBytes()); - // Поля "кому" (для сообщений/трансферов) пока пустые e.setToLogin(null); e.setToBchName(null); e.setToBlockGlobalNumber(null); e.setToBlockHashe(null); - // UPSERT блока blocksDAO.upsert(c, e); } + + /* ===================================================================== */ + /* =============================== Utils ================================ */ + /* ===================================================================== */ + + private static byte[] concat(byte[] a, byte[] b) { + byte[] out = new byte[a.length + b.length]; + System.arraycopy(a, 0, out, 0, a.length); + System.arraycopy(b, 0, out, a.length, b.length); + return out; + } + + private static long safeAdd(long x, long y) { + // защита от переполнения long (маловероятно, но пусть будет) + long r = x + y; + if (((x ^ r) & (y ^ r)) < 0) { + throw new IllegalArgumentException("fileSizeBytes overflow: " + x + " + " + y); + } + return r; + } } \ No newline at end of file diff --git a/src/main/java/server/logic/InboundMessageProcessor.java b/src/main/java/server/logic/InboundMessageProcessor.java index 9d956a9..4a2a267 100644 --- a/src/main/java/server/logic/InboundMessageProcessor.java +++ b/src/main/java/server/logic/InboundMessageProcessor.java @@ -18,9 +18,9 @@ public final class InboundMessageProcessor { private static final Logger log = LoggerFactory.getLogger(InboundMessageProcessor.class); private static final Map 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.GET_BLOCKCHAIN,new GetBlockchainHandler() // WireCodes.Op.SEARCH_USERS, new SearchUsersHandler(), // WireCodes.Op.GET_LAST_BLOCK_INFO,new GetLastBlockInfoHandler() diff --git a/src/main/java/server/logic/ws_protocol/binary/handlers/GetBlockchainHandler.java b/src/main/java/server/logic/ws_protocol/binary/handlers/GetBlockchainHandler.java index f717c1f..8495dde 100644 --- a/src/main/java/server/logic/ws_protocol/binary/handlers/GetBlockchainHandler.java +++ b/src/main/java/server/logic/ws_protocol/binary/handlers/GetBlockchainHandler.java @@ -1,53 +1,53 @@ -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(); - } -} +//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(); +// } +//}