SHA256
10 12 25
Добавил таблицы для геолокации
This commit is contained in:
@@ -19,6 +19,7 @@ import java.sql.Statement;
|
||||
* - solana_users
|
||||
* - active_sessions
|
||||
* - users_params
|
||||
* - ip_geo_cache
|
||||
*/
|
||||
public class DatabaseInitializer {
|
||||
|
||||
@@ -95,7 +96,7 @@ public class DatabaseInitializer {
|
||||
""");
|
||||
|
||||
// 2. Таблица active_sessions
|
||||
// sessionId теперь TEXT (base64 от 32 байт), а не INTEGER.
|
||||
// sessionId TEXT (base64 от 32 байт).
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS active_sessions (
|
||||
sessionId TEXT NOT NULL PRIMARY KEY,
|
||||
@@ -136,6 +137,20 @@ public class DatabaseInitializer {
|
||||
CREATE INDEX IF NOT EXISTS idx_users_params_loginId
|
||||
ON users_params (loginId);
|
||||
""");
|
||||
|
||||
// 4. Таблица ip_geo_cache — персистентный кэш геолокации по IP
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS ip_geo_cache (
|
||||
ip TEXT NOT NULL PRIMARY KEY,
|
||||
geo TEXT,
|
||||
updated_at_ms INTEGER NOT NULL
|
||||
);
|
||||
""");
|
||||
|
||||
st.executeUpdate("""
|
||||
CREATE INDEX IF NOT EXISTS idx_ip_geo_cache_updated_at
|
||||
ON ip_geo_cache (updated_at_ms);
|
||||
""");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package shine.db.dao;
|
||||
|
||||
import shine.db.SqliteDbController;
|
||||
import shine.db.entities.IpGeoCacheEntry;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/**
|
||||
* DAO для таблицы ip_geo_cache.
|
||||
*
|
||||
* Таблица:
|
||||
* - ip TEXT PRIMARY KEY
|
||||
* - geo TEXT
|
||||
* - updated_at_ms INTEGER NOT NULL
|
||||
*/
|
||||
public final class IpGeoCacheDAO {
|
||||
|
||||
private static volatile IpGeoCacheDAO instance;
|
||||
private final SqliteDbController db = SqliteDbController.getInstance();
|
||||
|
||||
private IpGeoCacheDAO() {
|
||||
}
|
||||
|
||||
public static IpGeoCacheDAO getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (IpGeoCacheDAO.class) {
|
||||
if (instance == null) {
|
||||
instance = new IpGeoCacheDAO();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* UPSERT по ip.
|
||||
* Если записи нет — вставляем.
|
||||
* Если есть — обновляем geo и updated_at_ms.
|
||||
*/
|
||||
public void upsert(IpGeoCacheEntry entry) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO ip_geo_cache (ip, geo, updated_at_ms)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT(ip)
|
||||
DO UPDATE SET
|
||||
geo = excluded.geo,
|
||||
updated_at_ms = excluded.updated_at_ms
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setString(1, entry.getIp());
|
||||
ps.setString(2, entry.getGeo());
|
||||
ps.setLong(3, entry.getUpdatedAtMs());
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить запись по IP.
|
||||
* Если нет — возвращает null.
|
||||
*/
|
||||
public IpGeoCacheEntry getByIp(String ip) throws SQLException {
|
||||
String sql = """
|
||||
SELECT ip, geo, updated_at_ms
|
||||
FROM ip_geo_cache
|
||||
WHERE ip = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setString(1, ip);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) {
|
||||
return null;
|
||||
}
|
||||
return mapRow(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Опционально — очистка старых записей.
|
||||
* Можно вызывать по расписанию, если нужно.
|
||||
*/
|
||||
public int deleteOlderThan(long thresholdMs) throws SQLException {
|
||||
String sql = "DELETE FROM ip_geo_cache WHERE updated_at_ms < ?";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, thresholdMs);
|
||||
return ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private IpGeoCacheEntry mapRow(ResultSet rs) throws SQLException {
|
||||
String ip = rs.getString("ip");
|
||||
String geo = rs.getString("geo");
|
||||
long updatedAtMs = rs.getLong("updated_at_ms");
|
||||
return new IpGeoCacheEntry(ip, geo, updatedAtMs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package shine.db.entities;
|
||||
|
||||
/**
|
||||
* Запись в таблице ip_geo_cache.
|
||||
*
|
||||
* Храним:
|
||||
* - ip — строка IP-адреса (PRIMARY KEY)
|
||||
* - geo — строка "Country, City" или любое текстовое описание
|
||||
* - updatedAtMs — время последнего обновления (Unix time в мс)
|
||||
*/
|
||||
public class IpGeoCacheEntry {
|
||||
|
||||
private String ip;
|
||||
private String geo;
|
||||
private long updatedAtMs;
|
||||
|
||||
public IpGeoCacheEntry() {
|
||||
}
|
||||
|
||||
public IpGeoCacheEntry(String ip, String geo, long updatedAtMs) {
|
||||
this.ip = ip;
|
||||
this.geo = geo;
|
||||
this.updatedAtMs = updatedAtMs;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getGeo() {
|
||||
return geo;
|
||||
}
|
||||
|
||||
public void setGeo(String geo) {
|
||||
this.geo = geo;
|
||||
}
|
||||
|
||||
public long getUpdatedAtMs() {
|
||||
return updatedAtMs;
|
||||
}
|
||||
|
||||
public void setUpdatedAtMs(long updatedAtMs) {
|
||||
this.updatedAtMs = updatedAtMs;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user