Добавить временную бесплатную загрузку аватаров в Arweave

This commit is contained in:
AidarKC
2026-06-20 21:29:35 +04:00
parent d0e7998650
commit dd35e56029
20 changed files with 1236 additions and 6 deletions
@@ -264,6 +264,21 @@ public final class DatabaseInitializer {
ON ip_geo_cache (updated_at_ms);
""");
st.executeUpdate("""
CREATE TABLE IF NOT EXISTS test_free_avatar_uploads (
login TEXT NOT NULL PRIMARY KEY COLLATE NOCASE,
used_count INTEGER NOT NULL DEFAULT 0,
updated_at_ms INTEGER NOT NULL,
last_tx_id TEXT NOT NULL DEFAULT '',
FOREIGN KEY (login) REFERENCES solana_users(login)
);
""");
st.executeUpdate("""
CREATE INDEX IF NOT EXISTS idx_test_free_avatar_uploads_updated
ON test_free_avatar_uploads (updated_at_ms);
""");
// 5. blockchain_state
st.executeUpdate("""
CREATE TABLE IF NOT EXISTS blockchain_state (
@@ -14,7 +14,7 @@ import java.sql.Statement;
public final class SqliteDbController {
private static volatile SqliteDbController instance;
private static final int LATEST_SCHEMA_VERSION = 7;
private static final int LATEST_SCHEMA_VERSION = 8;
private final String jdbcUrl;
@@ -90,6 +90,7 @@ public final class SqliteDbController {
case 5 -> migrateToV5();
case 6 -> migrateToV6();
case 7 -> migrateToV7();
case 8 -> migrateToV8();
default -> throw new RuntimeException("Unknown DB migration target version: " + targetVersion);
}
}
@@ -249,6 +250,25 @@ public final class SqliteDbController {
}
}
private void migrateToV8() {
try (Connection c = DriverManager.getConnection(jdbcUrl);
Statement st = c.createStatement()) {
c.setAutoCommit(false);
try {
ensureTestFreeAvatarUploadsTable(st);
setSchemaVersion(c, 8);
c.commit();
} catch (Exception e) {
try { c.rollback(); } catch (Exception ignored) {}
throw new RuntimeException("DB migration to v8 failed", e);
} finally {
try { c.setAutoCommit(true); } catch (Exception ignored) {}
}
} catch (SQLException e) {
throw new RuntimeException("DB migration to v8 failed", e);
}
}
private static void ensureChat200StateTables(Statement st) throws SQLException {
st.executeUpdate("""
CREATE TABLE IF NOT EXISTS chat200_state (
@@ -432,6 +452,22 @@ public final class SqliteDbController {
""");
}
private static void ensureTestFreeAvatarUploadsTable(Statement st) throws SQLException {
st.executeUpdate("""
CREATE TABLE IF NOT EXISTS test_free_avatar_uploads (
login TEXT NOT NULL PRIMARY KEY COLLATE NOCASE,
used_count INTEGER NOT NULL DEFAULT 0,
updated_at_ms INTEGER NOT NULL,
last_tx_id TEXT NOT NULL DEFAULT '',
FOREIGN KEY (login) REFERENCES solana_users(login)
);
""");
st.executeUpdate("""
CREATE INDEX IF NOT EXISTS idx_test_free_avatar_uploads_updated
ON test_free_avatar_uploads (updated_at_ms);
""");
}
private static void createConnectionsStateTable(Statement st) throws SQLException {
st.executeUpdate("""
@@ -0,0 +1,82 @@
package shine.db.dao;
import shine.db.SqliteDbController;
import shine.db.entities.TestFreeAvatarUploadEntry;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public final class TestFreeAvatarUploadsDAO {
private static volatile TestFreeAvatarUploadsDAO instance;
private final SqliteDbController db = SqliteDbController.getInstance();
private TestFreeAvatarUploadsDAO() {
}
public static TestFreeAvatarUploadsDAO getInstance() {
if (instance == null) {
synchronized (TestFreeAvatarUploadsDAO.class) {
if (instance == null) instance = new TestFreeAvatarUploadsDAO();
}
}
return instance;
}
public TestFreeAvatarUploadEntry getByLogin(Connection c, String login) throws SQLException {
String sql = """
SELECT login, used_count, updated_at_ms, last_tx_id
FROM test_free_avatar_uploads
WHERE login = ? COLLATE NOCASE
LIMIT 1
""";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, login);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
return mapRow(rs);
}
}
}
public TestFreeAvatarUploadEntry getByLogin(String login) throws SQLException {
try (Connection c = db.getConnection()) {
return getByLogin(c, login);
}
}
public void upsertUsage(Connection c, String login, int usedCount, long updatedAtMs, String lastTxId) throws SQLException {
String sql = """
INSERT INTO test_free_avatar_uploads (login, used_count, updated_at_ms, last_tx_id)
VALUES (?, ?, ?, ?)
ON CONFLICT(login) DO UPDATE SET
used_count = excluded.used_count,
updated_at_ms = excluded.updated_at_ms,
last_tx_id = excluded.last_tx_id
""";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, login);
ps.setInt(2, usedCount);
ps.setLong(3, updatedAtMs);
ps.setString(4, lastTxId);
ps.executeUpdate();
}
}
public void upsertUsage(String login, int usedCount, long updatedAtMs, String lastTxId) throws SQLException {
try (Connection c = db.getConnection()) {
upsertUsage(c, login, usedCount, updatedAtMs, lastTxId);
}
}
private static TestFreeAvatarUploadEntry mapRow(ResultSet rs) throws SQLException {
return new TestFreeAvatarUploadEntry(
rs.getString("login"),
rs.getInt("used_count"),
rs.getLong("updated_at_ms"),
rs.getString("last_tx_id")
);
}
}
@@ -0,0 +1,50 @@
package shine.db.entities;
public class TestFreeAvatarUploadEntry {
private String login;
private int usedCount;
private long updatedAtMs;
private String lastTxId;
public TestFreeAvatarUploadEntry() {
}
public TestFreeAvatarUploadEntry(String login, int usedCount, long updatedAtMs, String lastTxId) {
this.login = login;
this.usedCount = usedCount;
this.updatedAtMs = updatedAtMs;
this.lastTxId = lastTxId;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public int getUsedCount() {
return usedCount;
}
public void setUsedCount(int usedCount) {
this.usedCount = usedCount;
}
public long getUpdatedAtMs() {
return updatedAtMs;
}
public void setUpdatedAtMs(long updatedAtMs) {
this.updatedAtMs = updatedAtMs;
}
public String getLastTxId() {
return lastTxId;
}
public void setLastTxId(String lastTxId) {
this.lastTxId = lastTxId;
}
}