Add more information to the individual cache pages

Signed-off-by: Graham <gpe@openrs2.org>
pull/132/head
Graham 3 years ago
parent d89c45940b
commit e0a2df889b
  1. 134
      archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt
  2. 104
      archive/src/main/resources/org/openrs2/archive/templates/caches/show.html

@ -5,11 +5,13 @@ import io.netty.buffer.ByteBufAllocator
import io.netty.buffer.Unpooled
import org.openrs2.buffer.use
import org.openrs2.cache.Js5Archive
import org.openrs2.cache.Js5Compression
import org.openrs2.cache.Js5MasterIndex
import org.openrs2.cache.MasterIndexFormat
import org.openrs2.cache.Store
import org.openrs2.crypto.XteaKey
import org.openrs2.db.Database
import java.time.Instant
import java.util.Collections
import java.util.SortedSet
import javax.inject.Inject
import javax.inject.Singleton
@ -50,19 +52,30 @@ public class CacheExporter @Inject constructor(
}
}
public data class Cache(
public data class CacheSummary(
val id: Int,
val games: SortedSet<String>,
val game: String,
val builds: SortedSet<Int>,
val timestamp: Instant?,
val names: SortedSet<String>,
val descriptions: List<String>,
val urls: SortedSet<String>,
val stats: Stats?
) {
val game: String
get() = games.single()
}
)
public data class Cache(
val id: Int,
val sources: List<Source>,
val stats: Stats?,
val masterIndex: Js5MasterIndex
)
public data class Source(
val game: String,
val build: Int?,
val timestamp: Instant?,
val name: String?,
val description: String?,
val url: String?
)
public data class Key(
val archive: Int,
@ -73,7 +86,7 @@ public class CacheExporter @Inject constructor(
val key: XteaKey
)
public suspend fun list(): List<Cache> {
public suspend fun list(): List<CacheSummary> {
return database.execute { connection ->
connection.prepareStatement(
"""
@ -100,7 +113,7 @@ public class CacheExporter @Inject constructor(
""".trimIndent()
).use { stmt ->
stmt.executeQuery().use { rows ->
val caches = mutableListOf<Cache>()
val caches = mutableListOf<CacheSummary>()
while (rows.next()) {
val id = rows.getInt(1)
@ -122,14 +135,12 @@ public class CacheExporter @Inject constructor(
null
}
caches += Cache(
caches += CacheSummary(
id,
sortedSetOf(game),
game,
builds.toSortedSet(),
timestamp,
names.toSortedSet(),
emptyList(),
Collections.emptySortedSet(),
stats
)
}
@ -142,15 +153,14 @@ public class CacheExporter @Inject constructor(
public suspend fun get(id: Int): Cache? {
return database.execute { connection ->
val masterIndex: Js5MasterIndex
val stats: Stats?
connection.prepareStatement(
"""
SELECT
array_remove(array_agg(DISTINCT g.name ORDER BY g.name ASC), NULL),
array_remove(array_agg(DISTINCT s.build ORDER BY s.build ASC), NULL),
MIN(s.timestamp),
array_remove(array_agg(DISTINCT s.name ORDER BY s.name ASC), NULL),
array_remove(array_agg(DISTINCT s.description), NULL),
array_remove(array_agg(DISTINCT s.url ORDER BY s.url ASC), NULL),
m.format,
c.data,
ms.valid_indexes,
ms.indexes,
ms.valid_groups,
@ -159,11 +169,9 @@ public class CacheExporter @Inject constructor(
ms.keys,
ms.size
FROM master_indexes m
JOIN sources s ON s.master_index_id = m.id
JOIN games g ON g.id = s.game_id
JOIN containers c ON c.id = m.container_id
LEFT JOIN master_index_stats ms ON ms.master_index_id = m.id
WHERE m.id = ?
GROUP BY m.id, ms.valid_indexes, ms.indexes, ms.valid_groups, ms.groups, ms.valid_keys, ms.keys, ms.size
""".trimIndent()
).use { stmt ->
stmt.setInt(1, id)
@ -173,38 +181,62 @@ public class CacheExporter @Inject constructor(
return@execute null
}
val games = rows.getArray(1).array as Array<String>
val builds = rows.getArray(2).array as Array<Int>
val timestamp = rows.getTimestamp(3)?.toInstant()
val names = rows.getArray(4).array as Array<String>
val descriptions = rows.getArray(5).array as Array<String>
val urls = rows.getArray(6).array as Array<String>
val validIndexes = rows.getLong(7)
val stats = if (!rows.wasNull()) {
val indexes = rows.getLong(8)
val validGroups = rows.getLong(9)
val groups = rows.getLong(10)
val validKeys = rows.getLong(11)
val keys = rows.getLong(12)
val size = rows.getLong(13)
Stats(validIndexes, indexes, validGroups, groups, validKeys, keys, size)
} else {
val format = MasterIndexFormat.valueOf(rows.getString(1).toUpperCase())
masterIndex = Unpooled.wrappedBuffer(rows.getBytes(2)).use { compressed ->
Js5Compression.uncompress(compressed).use { uncompressed ->
Js5MasterIndex.read(uncompressed, format)
}
}
val validIndexes = rows.getLong(3)
stats = if (rows.wasNull()) {
null
} else {
val indexes = rows.getLong(4)
val validGroups = rows.getLong(5)
val groups = rows.getLong(6)
val validKeys = rows.getLong(7)
val keys = rows.getLong(8)
val size = rows.getLong(9)
Stats(validIndexes, indexes, validGroups, groups, validKeys, keys, size)
}
}
}
val sources = mutableListOf<Source>()
return@execute Cache(
id,
games.toSortedSet(),
builds.toSortedSet(),
timestamp,
names.toSortedSet(),
descriptions.toList(),
urls.toSortedSet(),
stats
)
connection.prepareStatement(
"""
SELECT g.name, s.build, s.timestamp, s.name, s.description, s.url
FROM sources s
JOIN games g ON g.id = s.game_id
WHERE s.master_index_id = ?
ORDER BY s.name ASC
""".trimIndent()
).use { stmt ->
stmt.setInt(1, id)
stmt.executeQuery().use { rows ->
while (rows.next()) {
val game = rows.getString(1)
var build: Int? = rows.getInt(2)
if (rows.wasNull()) {
build = null
}
val timestamp = rows.getTimestamp(3)?.toInstant()
val name = rows.getString(4)
val description = rows.getString(5)
val url = rows.getString(6)
sources += Source(game, build, timestamp, name, description, url)
}
}
}
Cache(id, sources, stats, masterIndex)
}
}

@ -15,34 +15,8 @@
<!--/*@thymesVar id="cache" type="org.openrs2.archive.cache.CacheExporter.Cache"*/-->
<table class="table table-striped table-bordered table-hover">
<tr class="thead-dark">
<th>Game</th>
<td th:text="${#strings.setJoin(cache.games, ', ')}">runescape</td>
</tr>
<tr class="thead-dark">
<th>Build(s)</th>
<td th:text="${#strings.setJoin(cache.builds, ', ')}">550</td>
</tr>
<tr class="thead-dark">
<th>Timestamp</th>
<td th:text="${#temporals.format(cache.timestamp, 'yyyy-MM-dd HH:mm:ss')}"></td>
</tr>
<tr class="thead-dark">
<th>Source(s)</th>
<td th:text="${#strings.setJoin(cache.names, '/')}"></td>
</tr>
<tr class="thead-dark">
<th>Description</th>
<td th:text="${#strings.listJoin(cache.descriptions, ' ')}"></td>
</tr>
<tr class="thead-dark">
<th>URL(s)</th>
<td>
<ul>
<li th:each="url : ${cache.urls}">
<a th:href="${url}" th:text="${url}">https://www.example.com/</a>
</li>
</ul>
</td>
<th>Format</th>
<td th:text="${cache.masterIndex.format}">VERSIONED</td>
</tr>
<tr class="thead-dark">
<th>Indexes</th>
@ -88,6 +62,80 @@
</td>
</tr>
</table>
<h2>Sources</h2>
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover">
<thead class="thead-dark">
<tr>
<th>Game</th>
<th>Build</th>
<th>Timestamp</th>
<th>Name</th>
<th>Description</th>
<th>URL</th>
</tr>
</thead>
<tbody>
<tr th:each="source : ${cache.sources}">
<td th:text="${source.game}">runescape</td>
<td th:text="${source.build}" class="text-right">550</td>
<td th:text="${#temporals.format(source.timestamp, 'yyyy-MM-dd HH:mm:ss')}"></td>
<td th:text="${source.name}"></td>
<td th:text="${source.description}"></td>
<td>
<a th:href="${source.url}" th:text="${source.url}" th:if="${source.url}">https://www.example.com/</a>
</td>
</tr>
</tbody>
</table>
</div>
<h2>Master index</h2>
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover">
<thead class="thead-dark">
<tr>
<th>Archive</th>
<th>Version</th>
<th>Checksum</th>
<th>Digest</th>
<th>Groups</th>
<th>Total uncompressed length</th>
</tr>
</thead>
<tbody>
<tr th:each="entry, it : ${cache.masterIndex.entries}">
<td th:text="${it.index}" class="text-right">0</td>
<td th:text="${#numbers.formatInteger(entry.version, 1, 'COMMA')}" class="text-right">0</td>
<td class="text-right">
<code th:text="${entry.checksum}">0</code>
</td>
<td>
<code
th:if="${cache.masterIndex.format >= @org.openrs2.cache.MasterIndexFormat@DIGESTS}"><span
th:remove="tag"
th:text="${@io.netty.buffer.ByteBufUtil@hexDump(entry.digest).substring(0, 64)}"></span>&ZeroWidthSpace;<span
th:remove="tag"
th:text="${@io.netty.buffer.ByteBufUtil@hexDump(entry.digest).substring(64)}"></span></code>
</td>
<td class="text-right">
<span
th:if="${cache.masterIndex.format >= @org.openrs2.cache.MasterIndexFormat@LENGTHS}"
th:text="${#numbers.formatInteger(entry.groups, 1, 'COMMA')}"></span>
</td>
<td class="text-right">
<!--/*@thymesVar id="#byteunits" type="org.openrs2.archive.web.ByteUnits"*/-->
<span
th:if="${cache.masterIndex.format >= @org.openrs2.cache.MasterIndexFormat@LENGTHS}"
th:text="${#byteunits.format(@java.lang.Integer@toUnsignedLong(entry.totalUncompressedLength))}"></span>
</td>
</tr>
</tbody>
</table>
</div>
</main>
</body>
</html>

Loading…
Cancel
Save