diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt index b0f34ab3..b607efcd 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt @@ -20,14 +20,15 @@ public class CacheExporter @Inject constructor( val whirlpool: ByteArray, val game: String, val build: Int?, - val timestamp: Instant? + val timestamp: Instant?, + val name: String? ) public suspend fun list(): List { return database.execute { connection -> connection.prepareStatement( """ - SELECT c.id, c.whirlpool, g.name, m.build, m.timestamp + SELECT c.id, c.whirlpool, g.name, m.build, m.timestamp, m.name FROM master_indexes m JOIN games g ON g.id = m.game_id JOIN containers c ON c.id = m.container_id @@ -48,8 +49,9 @@ public class CacheExporter @Inject constructor( } val timestamp = rows.getTimestamp(5)?.toInstant() + val name = rows.getString(6) - caches += Cache(id, whirlpool, game, build, timestamp) + caches += Cache(id, whirlpool, game, build, timestamp, name) } caches diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt index b5c9bd32..84255837 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt @@ -60,7 +60,14 @@ public class CacheImporter @Inject constructor( encrypted: Boolean ) : Container(data, encrypted) - public suspend fun import(store: Store, game: String, build: Int?, timestamp: Instant?) { + public suspend fun import( + store: Store, + game: String, + build: Int?, + timestamp: Instant?, + name: String?, + description: String? + ) { database.execute { connection -> prepare(connection) @@ -69,7 +76,7 @@ public class CacheImporter @Inject constructor( // import master index val masterIndex = createMasterIndex(store) try { - addMasterIndex(connection, masterIndex, gameId, build, timestamp) + addMasterIndex(connection, masterIndex, gameId, build, timestamp, name, description) } finally { masterIndex.release() } @@ -118,7 +125,14 @@ public class CacheImporter @Inject constructor( } } - public suspend fun importMasterIndex(buf: ByteBuf, game: String, build: Int?, timestamp: Instant?) { + public suspend fun importMasterIndex( + buf: ByteBuf, + game: String, + build: Int?, + timestamp: Instant?, + name: String?, + description: String? + ) { Js5Compression.uncompress(buf.slice()).use { uncompressed -> val masterIndex = MasterIndex(Js5MasterIndex.read(uncompressed.slice()), buf) @@ -126,7 +140,7 @@ public class CacheImporter @Inject constructor( prepare(connection) val gameId = getGameId(connection, game) - addMasterIndex(connection, masterIndex, gameId, build, timestamp) + addMasterIndex(connection, masterIndex, gameId, build, timestamp, name, description) } } } @@ -136,7 +150,8 @@ public class CacheImporter @Inject constructor( buf: ByteBuf, gameId: Int, build: Int, - timestamp: Instant + timestamp: Instant, + name: String, ): List { return database.execute { connection -> prepare(connection) @@ -154,7 +169,7 @@ public class CacheImporter @Inject constructor( stmt.execute() } - addMasterIndex(connection, MasterIndex(masterIndex, buf), gameId, build, timestamp) + addMasterIndex(connection, MasterIndex(masterIndex, buf), gameId, build, timestamp, name, null) connection.prepareStatement( """ @@ -302,21 +317,32 @@ public class CacheImporter @Inject constructor( connection: Connection, masterIndex: MasterIndex, gameId: Int, - build: Int? = null, - timestamp: Instant? = null + build: Int?, + timestamp: Instant?, + name: String?, + description: String? ) { val containerId = addContainer(connection, masterIndex) - val savepoint = connection.setSavepoint() - // TODO(gpe): override game_id/build/timestamp if they're null? + // TODO(gpe): combine name/description instead of overwriting one with the other? + // or a mechanism to control priority? connection.prepareStatement( """ - INSERT INTO master_indexes (container_id, game_id, build, timestamp) - VALUES (?, ?, ?, ?) + INSERT INTO master_indexes (container_id, game_id, build, timestamp, name, description) + VALUES (?, ?, ?, ?, ?, ?) + ON CONFLICT (container_id) DO UPDATE SET + build = COALESCE(EXCLUDED.build, master_indexes.build), + timestamp = COALESCE( + LEAST(EXCLUDED.timestamp, master_indexes.timestamp), + EXCLUDED.timestamp, + master_indexes.timestamp + ), + name = COALESCE(EXCLUDED.name, master_indexes.name), + description = COALESCE(EXCLUDED.description, master_indexes.description) """.trimIndent() ).use { stmt -> stmt.setLong(1, containerId) - stmt.setObject(2, gameId, Types.INTEGER) + stmt.setInt(2, gameId) stmt.setObject(3, build, Types.INTEGER) if (timestamp != null) { @@ -326,21 +352,17 @@ public class CacheImporter @Inject constructor( stmt.setNull(4, Types.TIMESTAMP_WITH_TIMEZONE) } - try { - stmt.execute() - } catch (ex: SQLException) { - if (ex.sqlState == PSQLState.UNIQUE_VIOLATION.state) { - connection.rollback(savepoint) - return@addMasterIndex - } - throw ex - } + stmt.setString(5, name) + stmt.setString(6, description) + + stmt.execute() } connection.prepareStatement( """ INSERT INTO master_index_archives (container_id, archive_id, crc32, version) VALUES (?, ?, ?, ?) + ON CONFLICT DO NOTHING """.trimIndent() ).use { stmt -> for ((i, entry) in masterIndex.index.entries.withIndex()) { diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/ImportCommand.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/ImportCommand.kt index 4cfc4e75..dacd90b2 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/ImportCommand.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/ImportCommand.kt @@ -14,6 +14,8 @@ import org.openrs2.cli.instant public class ImportCommand : CliktCommand(name = "import") { private val build by option().int() private val timestamp by option().instant() + private val name by option() + private val description by option() private val game by argument() private val input by argument().path( @@ -27,7 +29,7 @@ public class ImportCommand : CliktCommand(name = "import") { val importer = injector.getInstance(CacheImporter::class.java) Store.open(input).use { store -> - importer.import(store, game, build, timestamp) + importer.import(store, game, build, timestamp, name, description) } } } diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/ImportMasterIndexCommand.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/ImportMasterIndexCommand.kt index f576cfc1..0577d554 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/ImportMasterIndexCommand.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/ImportMasterIndexCommand.kt @@ -16,6 +16,8 @@ import java.nio.file.Files public class ImportMasterIndexCommand : CliktCommand(name = "import-master-index") { private val build by option().int() private val timestamp by option().instant() + private val name by option() + private val description by option() private val game by argument() private val input by argument().path( @@ -29,7 +31,7 @@ public class ImportMasterIndexCommand : CliktCommand(name = "import-master-index val importer = injector.getInstance(CacheImporter::class.java) Unpooled.wrappedBuffer(Files.readAllBytes(input)).use { buf -> - importer.importMasterIndex(buf, game, build, timestamp) + importer.importMasterIndex(buf, game, build, timestamp, name, description) } } } diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/Js5ChannelHandler.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/Js5ChannelHandler.kt index c3c2d4fd..04a7fae9 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/Js5ChannelHandler.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/Js5ChannelHandler.kt @@ -158,7 +158,8 @@ public class Js5ChannelHandler( } val rawIndexes = runBlocking { - importer.importMasterIndexAndGetIndexes(masterIndex!!, buf, gameId, build, Instant.now()) + val name = "Downloaded from $hostname:$port" + importer.importMasterIndexAndGetIndexes(masterIndex!!, buf, gameId, build, Instant.now(), name) } try { indexes = arrayOfNulls(rawIndexes.size) diff --git a/archive/src/main/resources/org/openrs2/archive/V1__init.sql b/archive/src/main/resources/org/openrs2/archive/V1__init.sql index dff03f0a..cf014e63 100644 --- a/archive/src/main/resources/org/openrs2/archive/V1__init.sql +++ b/archive/src/main/resources/org/openrs2/archive/V1__init.sql @@ -86,7 +86,9 @@ CREATE TABLE master_indexes ( container_id BIGINT PRIMARY KEY NOT NULL REFERENCES containers (id), game_id INTEGER NOT NULL REFERENCES games (id), build INTEGER NULL, - timestamp TIMESTAMPTZ NULL + timestamp TIMESTAMPTZ NULL, + name TEXT NULL, + description TEXT NULL ); CREATE TABLE master_index_archives ( diff --git a/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html b/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html index 2ab01876..40ffa4bc 100644 --- a/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html +++ b/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html @@ -8,6 +8,7 @@ Game Build Timestamp + Name @@ -18,6 +19,7 @@ runescape 550 + Download