package shine.db.dao; import shine.db.SqliteDbController; import shine.db.entities.SolanaUserEntry; import java.sql.*; /** * UserCreateDAO — атомарное добавление пользователя: * - solana_users (login, blockchain_name, solana_key, blockchain_key, device_key) * - blockchain_state (blockchain_name, login, blockchain_key, size_limit, ... last_block_number=-1 ...) * * ВАЖНО: * - только INSERT (без перезаписи существующих записей) * - если login или blockchainName заняты — возвращаем false (пользователь уже есть/занято) */ public final class UserCreateDAO { private static volatile UserCreateDAO instance; private final SqliteDbController db = SqliteDbController.getInstance(); private final SolanaUsersDAO usersDao = SolanaUsersDAO.getInstance(); private UserCreateDAO() {} public static UserCreateDAO getInstance() { if (instance == null) { synchronized (UserCreateDAO.class) { if (instance == null) instance = new UserCreateDAO(); } } return instance; } /** * @return true если добавили; false если занято (login уже есть или blockchainName уже существует). */ public boolean insertUserWithBlockchain( String login, String blockchainName, String solanaKey, String blockchainKey, String deviceKey, long sizeLimit, long nowMs ) throws SQLException { try (Connection c = db.getConnection()) { boolean oldAuto = c.getAutoCommit(); c.setAutoCommit(false); try { // 1) solana_users SolanaUserEntry u = new SolanaUserEntry(); u.setLogin(login); u.setBlockchainName(blockchainName); u.setSolanaKey(solanaKey); u.setBlockchainKey(blockchainKey); u.setDeviceKey(deviceKey); usersDao.insert(c, u); // если login занят (NOCASE) или blockchainName (unique) -> constraint // 2) blockchain_state — строго INSERT, без UPSERT (иначе можно перезаписать существующую цепочку) insertBlockchainStateStrict( c, blockchainName, login, blockchainKey, sizeLimit, nowMs ); c.commit(); return true; } catch (SQLException e) { c.rollback(); String msg = e.getMessage() == null ? "" : e.getMessage().toLowerCase(); if (msg.contains("constraint")) { return false; } throw e; } finally { c.setAutoCommit(oldAuto); } } } private static void insertBlockchainStateStrict( Connection c, String blockchainName, String login, String blockchainKey, long sizeLimit, long nowMs ) throws SQLException { String sql = """ INSERT INTO blockchain_state ( blockchain_name, login, blockchain_key, size_limit, file_size_bytes, last_block_number, last_block_hash, updated_at_ms ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """; try (PreparedStatement ps = c.prepareStatement(sql)) { int i = 1; ps.setString(i++, blockchainName); ps.setString(i++, login); ps.setString(i++, blockchainKey); ps.setLong(i++, sizeLimit); ps.setLong(i++, 0L); ps.setInt(i++, -1); ps.setNull(i++, Types.BLOB); // старт: блоков ещё нет ps.setLong(i++, nowMs); ps.executeUpdate(); // если blockchainName занят -> constraint (PK) } } }