SHA256
Старт
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package shine.db;
|
||||
|
||||
|
||||
import utils.config.AppConfig;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.*;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
public class DatabaseInitializer {
|
||||
|
||||
public static void createNewDB(String[] args) {
|
||||
AppConfig config = AppConfig.getInstance();
|
||||
String dbPath = config.getParam("db.path");
|
||||
|
||||
if (dbPath == null || dbPath.isBlank()) {
|
||||
System.err.println("Параметр db.path не задан в application.properties");
|
||||
return;
|
||||
}
|
||||
|
||||
Path dbFile = Paths.get(dbPath);
|
||||
try {
|
||||
// создаём директорию, если нужно
|
||||
Path parent = dbFile.getParent();
|
||||
if (parent != null && !Files.exists(parent)) {
|
||||
Files.createDirectories(parent);
|
||||
}
|
||||
|
||||
if (Files.exists(dbFile)) {
|
||||
System.out.println("Файл базы данных уже существует: " + dbFile.toAbsolutePath());
|
||||
System.out.print("Пересоздать БД (СТАРАЯ БУДЕТ УДАЛЕНА)? [y/N]: ");
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
String answer = reader.readLine();
|
||||
if (!"y".equalsIgnoreCase(answer) && !"yes".equalsIgnoreCase(answer)) {
|
||||
System.out.println("Операция отменена. БД не изменена.");
|
||||
return;
|
||||
}
|
||||
|
||||
Files.delete(dbFile);
|
||||
System.out.println("Старый файл БД удалён.");
|
||||
}
|
||||
|
||||
createSchema("jdbc:sqlite:" + dbPath);
|
||||
System.out.println("Новая БД успешно создана по пути: " + dbFile.toAbsolutePath());
|
||||
|
||||
} catch (IOException e) {
|
||||
System.err.println("Ошибка работы с файлом БД: " + e.getMessage());
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Ошибка создания схемы БД: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSchema(String jdbcUrl) throws SQLException {
|
||||
try {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("SQLite JDBC driver not found", e);
|
||||
}
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(jdbcUrl);
|
||||
Statement st = conn.createStatement()) {
|
||||
|
||||
// включаем внешние ключи на этом соединении (для инициализации тоже)
|
||||
st.execute("PRAGMA foreign_keys = ON");
|
||||
|
||||
// 1. Таблица solana_users
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS solana_users (
|
||||
login TEXT NOT NULL,
|
||||
loginId INTEGER NOT NULL PRIMARY KEY,
|
||||
bchId INTEGER NOT NULL,
|
||||
pubkey0 TEXT,
|
||||
pubkey1 TEXT,
|
||||
bchLimit INTEGER -- может быть NULL
|
||||
);
|
||||
""");
|
||||
|
||||
st.executeUpdate("""
|
||||
CREATE INDEX IF NOT EXISTS idx_solana_users_login
|
||||
ON solana_users (login);
|
||||
""");
|
||||
|
||||
// 2. Таблица active_sessions
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS active_sessions (
|
||||
sessionId INTEGER NOT NULL PRIMARY KEY,
|
||||
session_pwd TEXT NOT NULL,
|
||||
loginId INTEGER NOT NULL,
|
||||
time_ms INTEGER NOT NULL,
|
||||
pubkey_num INTEGER NOT NULL,
|
||||
push_endpoint TEXT,
|
||||
push_p256dh_key TEXT,
|
||||
push_auth_key TEXT,
|
||||
FOREIGN KEY (loginId) REFERENCES solana_users(loginId)
|
||||
);
|
||||
""");
|
||||
|
||||
// 3. Таблица users_params
|
||||
// Важно: пара (loginId, param) должна быть уникальна
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS users_params (
|
||||
loginId INTEGER NOT NULL,
|
||||
param TEXT NOT NULL,
|
||||
bch_channel_id INTEGER NOT NULL DEFAULT 0,
|
||||
value TEXT,
|
||||
time_ms INTEGER NOT NULL,
|
||||
pubkey_num INTEGER NOT NULL,
|
||||
signature TEXT,
|
||||
FOREIGN KEY (loginId) REFERENCES solana_users(loginId),
|
||||
UNIQUE (loginId, param)
|
||||
);
|
||||
""");
|
||||
|
||||
st.executeUpdate("""
|
||||
CREATE INDEX IF NOT EXISTS idx_users_params_loginId
|
||||
ON users_params (loginId);
|
||||
""");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package shine.db;
|
||||
|
||||
import shine.db.dao.ActiveSessionsDAO;
|
||||
import utils.config.AppConfig;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
public final class SqliteDbController {
|
||||
|
||||
private static volatile SqliteDbController instance;
|
||||
private final Connection connection;
|
||||
|
||||
private SqliteDbController() {
|
||||
try {
|
||||
// Подгружаем драйвер SQLite
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("SQLite JDBC driver not found", e);
|
||||
}
|
||||
|
||||
String dbPath = AppConfig.getInstance().getParam("db.path");
|
||||
|
||||
if (dbPath == null || dbPath.isBlank()) {
|
||||
throw new RuntimeException("Config param 'db.path' is not set in application.properties");
|
||||
}
|
||||
|
||||
Path dbFile = Paths.get(dbPath);
|
||||
|
||||
// 👉 Если файла БД нет — создаём новую БД через DatabaseInitializer
|
||||
if (!Files.exists(dbFile)) {
|
||||
System.out.println("[DB] Файл БД не найден: " + dbFile.toAbsolutePath());
|
||||
System.out.println("[DB] Создаём новую БД с помощью DatabaseInitializer...");
|
||||
|
||||
// можно передать пустой массив аргументов
|
||||
DatabaseInitializer.createNewDB(new String[0]);
|
||||
}
|
||||
|
||||
String url = "jdbc:sqlite:" + dbPath;
|
||||
|
||||
try {
|
||||
this.connection = DriverManager.getConnection(url);
|
||||
this.connection.setAutoCommit(true);
|
||||
|
||||
// ВАЖНО: включаем поддержку внешних ключей для этого соединения
|
||||
try (Statement st = this.connection.createStatement()) {
|
||||
st.execute("PRAGMA foreign_keys = ON");
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Failed to connect to SQLite database: " + url, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SqliteDbController getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (SqliteDbController.class) {
|
||||
if (instance == null) {
|
||||
instance = new SqliteDbController();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
// логировать по необходимости
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package shine.db.dao;
|
||||
|
||||
import shine.db.SqliteDbController;
|
||||
import shine.db.entities.ActiveSession;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/** Здесь мы хрним данные об активных сессиях пользователя (для wss соединений) */
|
||||
|
||||
public final class ActiveSessionsDAO {
|
||||
|
||||
private static volatile ActiveSessionsDAO instance;
|
||||
private final SqliteDbController db = SqliteDbController.getInstance();
|
||||
|
||||
private ActiveSessionsDAO() {
|
||||
}
|
||||
|
||||
public static ActiveSessionsDAO getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (ActiveSessionsDAO.class) {
|
||||
if (instance == null) {
|
||||
instance = new ActiveSessionsDAO();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void insert(ActiveSession session) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO active_sessions (
|
||||
sessionId,
|
||||
session_pwd,
|
||||
loginId,
|
||||
time_ms,
|
||||
pubkey_num,
|
||||
push_endpoint,
|
||||
push_p256dh_key,
|
||||
push_auth_key
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, session.getSessionId());
|
||||
ps.setString(2, session.getSessionPwd());
|
||||
ps.setLong(3, session.getLoginId());
|
||||
ps.setLong(4, session.getTimeMs());
|
||||
ps.setInt(5, session.getPubkeyNum());
|
||||
ps.setString(6, session.getPushEndpoint());
|
||||
ps.setString(7, session.getPushP256dhKey());
|
||||
ps.setString(8, session.getPushAuthKey());
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public ActiveSession getBySessionId(long sessionId) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
sessionId,
|
||||
session_pwd,
|
||||
loginId,
|
||||
time_ms,
|
||||
pubkey_num,
|
||||
push_endpoint,
|
||||
push_p256dh_key,
|
||||
push_auth_key
|
||||
FROM active_sessions
|
||||
WHERE sessionId = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, sessionId);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) {
|
||||
return null;
|
||||
}
|
||||
return mapRow(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаление записи по sessionId.
|
||||
* Если записи нет — просто ничего не удалит (0 строк).
|
||||
*/
|
||||
public void deleteBySessionId(long sessionId) throws SQLException {
|
||||
String sql = "DELETE FROM active_sessions WHERE sessionId = ?";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, sessionId);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private ActiveSession mapRow(ResultSet rs) throws SQLException {
|
||||
long sessionId = rs.getLong("sessionId");
|
||||
String sessionPwd = rs.getString("session_pwd");
|
||||
long loginId = rs.getLong("loginId");
|
||||
long timeMs = rs.getLong("time_ms");
|
||||
short pubkeyNum = (short) rs.getInt("pubkey_num");
|
||||
String pushEndpoint = rs.getString("push_endpoint");
|
||||
String pushP256dhKey = rs.getString("push_p256dh_key");
|
||||
String pushAuthKey = rs.getString("push_auth_key");
|
||||
|
||||
return new ActiveSession(
|
||||
sessionId,
|
||||
sessionPwd,
|
||||
loginId,
|
||||
timeMs,
|
||||
pubkeyNum,
|
||||
pushEndpoint,
|
||||
pushP256dhKey,
|
||||
pushAuthKey
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package shine.db.dao;
|
||||
|
||||
import shine.db.SqliteDbController;
|
||||
import shine.db.entities.SolanaUser;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Здесь храним данные об пользователях - локальная копия того что есть в солане */
|
||||
|
||||
public final class SolanaUsersDAO {
|
||||
|
||||
private static volatile SolanaUsersDAO instance;
|
||||
private final SqliteDbController db = SqliteDbController.getInstance();
|
||||
|
||||
private SolanaUsersDAO() {}
|
||||
|
||||
public static SolanaUsersDAO getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (SolanaUsersDAO.class) {
|
||||
if (instance == null) {
|
||||
instance = new SolanaUsersDAO();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void insert(SolanaUser user) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO solana_users (login, loginId, bchId, pubkey0, pubkey1, bchLimit)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setString(1, user.getLogin());
|
||||
ps.setLong(2, user.getLoginId());
|
||||
ps.setLong(3, user.getBchId());
|
||||
ps.setString(4, user.getPubkey0());
|
||||
ps.setString(5, user.getPubkey1());
|
||||
|
||||
if (user.getBchLimit() != null) {
|
||||
ps.setInt(6, user.getBchLimit());
|
||||
} else {
|
||||
ps.setNull(6, Types.INTEGER);
|
||||
}
|
||||
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public SolanaUser getByLoginId(long loginId) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, loginId, bchId, pubkey0, pubkey1, bchLimit
|
||||
FROM solana_users
|
||||
WHERE loginId = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, loginId);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) return null;
|
||||
return mapRow(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SolanaUser getByLogin(String login) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, loginId, bchId, pubkey0, pubkey1, bchLimit
|
||||
FROM solana_users
|
||||
WHERE LOWER(login) = LOWER(?)
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setString(1, login);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) return null;
|
||||
return mapRow(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<SolanaUser> searchByLoginPrefix(String prefix) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, loginId, bchId, pubkey0, pubkey1, bchLimit
|
||||
FROM solana_users
|
||||
WHERE LOWER(login) LIKE ?
|
||||
ORDER BY login
|
||||
LIMIT 5
|
||||
""";
|
||||
|
||||
List<SolanaUser> result = new ArrayList<>();
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setString(1, prefix.toLowerCase() + "%");
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) result.add(mapRow(rs));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private SolanaUser mapRow(ResultSet rs) throws SQLException {
|
||||
return new SolanaUser(
|
||||
rs.getLong("loginId"),
|
||||
rs.getString("login"),
|
||||
rs.getLong("bchId"),
|
||||
rs.getString("pubkey0"),
|
||||
rs.getString("pubkey1"),
|
||||
rs.getObject("bchLimit") != null ? rs.getInt("bchLimit") : null
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package shine.db.dao;
|
||||
|
||||
import shine.db.SqliteDbController;
|
||||
import shine.db.entities.UserParam;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Здесь зраним сохранённые параметры пользователей (в основном до каково сообщения просмотрены ленты) */
|
||||
|
||||
public final class UserParamsDAO {
|
||||
|
||||
private static volatile UserParamsDAO instance;
|
||||
private final SqliteDbController db = SqliteDbController.getInstance();
|
||||
|
||||
private UserParamsDAO() {
|
||||
}
|
||||
|
||||
public static UserParamsDAO getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (UserParamsDAO.class) {
|
||||
if (instance == null) {
|
||||
instance = new UserParamsDAO();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* UPSERT методом ON CONFLICT — одним SQL-запросом.
|
||||
* Если запись существует -> обновляем поля.
|
||||
* Если нет -> вставляем новую запись.
|
||||
*/
|
||||
public void upsert(UserParam param) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO users_params (
|
||||
loginId,
|
||||
param,
|
||||
bch_channel_id,
|
||||
value,
|
||||
time_ms,
|
||||
pubkey_num,
|
||||
signature
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(loginId, param)
|
||||
DO UPDATE SET
|
||||
bch_channel_id = excluded.bch_channel_id,
|
||||
value = excluded.value,
|
||||
time_ms = excluded.time_ms,
|
||||
pubkey_num = excluded.pubkey_num,
|
||||
signature = excluded.signature
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, param.getLoginId());
|
||||
ps.setString(2, param.getParam());
|
||||
ps.setLong(3, param.getBchChannelId());
|
||||
ps.setString(4, param.getValue());
|
||||
ps.setLong(5, param.getTimeMs());
|
||||
ps.setInt(6, param.getPubkeyNum());
|
||||
ps.setString(7, param.getSignature());
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить параметр по loginId + param.
|
||||
*/
|
||||
public UserParam getByUserIdAndParam(long loginId, String paramName) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
loginId,
|
||||
param,
|
||||
bch_channel_id,
|
||||
value,
|
||||
time_ms,
|
||||
pubkey_num,
|
||||
signature
|
||||
FROM users_params
|
||||
WHERE loginId = ? AND param = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, loginId);
|
||||
ps.setString(2, paramName);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) return null;
|
||||
return mapRow(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить все параметры пользователя.
|
||||
*/
|
||||
public List<UserParam> getByUserId(long loginId) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
loginId,
|
||||
param,
|
||||
bch_channel_id,
|
||||
value,
|
||||
time_ms,
|
||||
pubkey_num,
|
||||
signature
|
||||
FROM users_params
|
||||
WHERE loginId = ?
|
||||
ORDER BY time_ms DESC
|
||||
""";
|
||||
|
||||
List<UserParam> result = new ArrayList<>();
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, loginId);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) result.add(mapRow(rs));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private UserParam mapRow(ResultSet rs) throws SQLException {
|
||||
return new UserParam(
|
||||
rs.getLong("loginId"),
|
||||
rs.getString("param"),
|
||||
rs.getLong("bch_channel_id"),
|
||||
rs.getString("value"),
|
||||
rs.getLong("time_ms"),
|
||||
(short) rs.getInt("pubkey_num"),
|
||||
rs.getString("signature")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package shine.db.entities;
|
||||
|
||||
public class ActiveSession {
|
||||
|
||||
private long sessionId;
|
||||
private String sessionPwd;
|
||||
private long loginId;
|
||||
private long timeMs; // время в мс
|
||||
private short pubkeyNum;
|
||||
private String pushEndpoint;
|
||||
private String pushP256dhKey;
|
||||
private String pushAuthKey;
|
||||
|
||||
public ActiveSession() {
|
||||
}
|
||||
|
||||
public ActiveSession(long sessionId,
|
||||
String sessionPwd,
|
||||
long loginId,
|
||||
long timeMs,
|
||||
short pubkeyNum,
|
||||
String pushEndpoint,
|
||||
String pushP256dhKey,
|
||||
String pushAuthKey) {
|
||||
this.sessionId = sessionId;
|
||||
this.sessionPwd = sessionPwd;
|
||||
this.loginId = loginId;
|
||||
this.timeMs = timeMs;
|
||||
this.pubkeyNum = pubkeyNum;
|
||||
this.pushEndpoint = pushEndpoint;
|
||||
this.pushP256dhKey = pushP256dhKey;
|
||||
this.pushAuthKey = pushAuthKey;
|
||||
}
|
||||
|
||||
public long getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(long sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public String getSessionPwd() {
|
||||
return sessionPwd;
|
||||
}
|
||||
|
||||
public void setSessionPwd(String sessionPwd) {
|
||||
this.sessionPwd = sessionPwd;
|
||||
}
|
||||
|
||||
public long getLoginId() {
|
||||
return loginId;
|
||||
}
|
||||
|
||||
public void setLoginId(long loginId) {
|
||||
this.loginId = loginId;
|
||||
}
|
||||
|
||||
public long getTimeMs() {
|
||||
return timeMs;
|
||||
}
|
||||
|
||||
public void setTimeMs(long timeMs) {
|
||||
this.timeMs = timeMs;
|
||||
}
|
||||
|
||||
public short getPubkeyNum() {
|
||||
return pubkeyNum;
|
||||
}
|
||||
|
||||
public void setPubkeyNum(short pubkeyNum) {
|
||||
this.pubkeyNum = pubkeyNum;
|
||||
}
|
||||
|
||||
public String getPushEndpoint() {
|
||||
return pushEndpoint;
|
||||
}
|
||||
|
||||
public void setPushEndpoint(String pushEndpoint) {
|
||||
this.pushEndpoint = pushEndpoint;
|
||||
}
|
||||
|
||||
public String getPushP256dhKey() {
|
||||
return pushP256dhKey;
|
||||
}
|
||||
|
||||
public void setPushP256dhKey(String pushP256dhKey) {
|
||||
this.pushP256dhKey = pushP256dhKey;
|
||||
}
|
||||
|
||||
public String getPushAuthKey() {
|
||||
return pushAuthKey;
|
||||
}
|
||||
|
||||
public void setPushAuthKey(String pushAuthKey) {
|
||||
this.pushAuthKey = pushAuthKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package shine.db.entities;
|
||||
|
||||
public class SolanaUser {
|
||||
|
||||
private long loginId;
|
||||
private String login;
|
||||
private long bchId;
|
||||
private String pubkey0;
|
||||
private String pubkey1;
|
||||
private Integer bchLimit; // может быть null
|
||||
|
||||
public SolanaUser() {
|
||||
}
|
||||
|
||||
public SolanaUser(long loginId,
|
||||
String login,
|
||||
long bchId,
|
||||
String pubkey0,
|
||||
String pubkey1,
|
||||
Integer bchLimit) {
|
||||
this.loginId = loginId;
|
||||
this.login = login;
|
||||
this.bchId = bchId;
|
||||
this.pubkey0 = pubkey0;
|
||||
this.pubkey1 = pubkey1;
|
||||
this.bchLimit = bchLimit;
|
||||
}
|
||||
|
||||
public long getLoginId() {
|
||||
return loginId;
|
||||
}
|
||||
|
||||
public void setLoginId(long loginId) {
|
||||
this.loginId = loginId;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
public long getBchId() {
|
||||
return bchId;
|
||||
}
|
||||
|
||||
public void setBchId(long bchId) {
|
||||
this.bchId = bchId;
|
||||
}
|
||||
|
||||
public String getPubkey0() {
|
||||
return pubkey0;
|
||||
}
|
||||
|
||||
public void setPubkey0(String pubkey0) {
|
||||
this.pubkey0 = pubkey0;
|
||||
}
|
||||
|
||||
public String getPubkey1() {
|
||||
return pubkey1;
|
||||
}
|
||||
|
||||
public void setPubkey1(String pubkey1) {
|
||||
this.pubkey1 = pubkey1;
|
||||
}
|
||||
|
||||
public Integer getBchLimit() {
|
||||
return bchLimit;
|
||||
}
|
||||
|
||||
public void setBchLimit(Integer bchLimit) {
|
||||
this.bchLimit = bchLimit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package shine.db.entities;
|
||||
|
||||
public class UserParam {
|
||||
|
||||
private long loginId;
|
||||
private String param;
|
||||
private long bchChannelId; // новый канал, 8 байт, может быть 0
|
||||
private String value;
|
||||
private long timeMs; // время в мс
|
||||
private short pubkeyNum;
|
||||
private String signature;
|
||||
|
||||
public UserParam() {
|
||||
}
|
||||
|
||||
public UserParam(long loginId,
|
||||
String param,
|
||||
long bchChannelId,
|
||||
String value,
|
||||
long timeMs,
|
||||
short pubkeyNum,
|
||||
String signature) {
|
||||
this.loginId = loginId;
|
||||
this.param = param;
|
||||
this.bchChannelId = bchChannelId;
|
||||
this.value = value;
|
||||
this.timeMs = timeMs;
|
||||
this.pubkeyNum = pubkeyNum;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public long getLoginId() {
|
||||
return loginId;
|
||||
}
|
||||
|
||||
public void setLoginId(long loginId) {
|
||||
this.loginId = loginId;
|
||||
}
|
||||
|
||||
public String getParam() {
|
||||
return param;
|
||||
}
|
||||
|
||||
public void setParam(String param) {
|
||||
this.param = param;
|
||||
}
|
||||
|
||||
public long getBchChannelId() {
|
||||
return bchChannelId;
|
||||
}
|
||||
|
||||
public void setBchChannelId(long bchChannelId) {
|
||||
this.bchChannelId = bchChannelId;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public long getTimeMs() {
|
||||
return timeMs;
|
||||
}
|
||||
|
||||
public void setTimeMs(long timeMs) {
|
||||
this.timeMs = timeMs;
|
||||
}
|
||||
|
||||
public short getPubkeyNum() {
|
||||
return pubkeyNum;
|
||||
}
|
||||
|
||||
public void setPubkeyNum(short pubkeyNum) {
|
||||
this.pubkeyNum = pubkeyNum;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Структура БД 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` только один раз.
|
||||
Reference in New Issue
Block a user