Open-source multiplayer game server compatible with the RuneScape client https://www.openrs2.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
openrs2/archive/src/main/kotlin/org/openrs2/archive/key/KeyExporter.kt

159 lines
4.7 KiB

package org.openrs2.archive.key
import jakarta.inject.Inject
import jakarta.inject.Singleton
import org.openrs2.crypto.SymmetricKey
import org.openrs2.db.Database
import java.io.BufferedOutputStream
import java.io.DataOutputStream
@Singleton
public class KeyExporter @Inject constructor(
private val database: Database
) {
public data class Stats(
val allKeys: Long,
val validKeys: Long,
val encryptedGroups: Long,
val validGroups: Long,
val emptyGroups: Long
) {
val validKeysFraction: Double = if (allKeys == 0L) {
1.0
} else {
validKeys.toDouble() / allKeys
}
val validGroupsFraction: Double = if (encryptedGroups == 0L) {
1.0
} else {
validGroups.toDouble() / encryptedGroups
}
val emptyGroupsFraction: Double = if (encryptedGroups == 0L) {
1.0
} else {
emptyGroups.toDouble() / encryptedGroups
}
}
public suspend fun count(): Stats {
return database.execute { connection ->
val encryptedGroups: Long
val validGroups: Long
val emptyGroups: Long
connection.prepareStatement(
"""
SELECT
COUNT(*),
COUNT(*) FILTER (WHERE c.key_id IS NOT NULL),
COUNT(*) FILTER (WHERE c.key_id IS NULL AND c.empty_loc)
FROM containers c
WHERE c.encrypted
""".trimIndent()
).use { stmt ->
stmt.executeQuery().use { rows ->
check(rows.next())
encryptedGroups = rows.getLong(1)
validGroups = rows.getLong(2)
emptyGroups = rows.getLong(3)
}
}
connection.prepareStatement(
"""
SELECT
COUNT(DISTINCT k.id),
COUNT(DISTINCT k.id) FILTER (WHERE c.key_id IS NOT NULL)
FROM keys k
LEFT JOIN containers c ON c.key_id = k.id
""".trimIndent()
).use { stmt ->
stmt.executeQuery().use { rows ->
check(rows.next())
val allKeys = rows.getLong(1)
val validKeys = rows.getLong(2)
Stats(allKeys, validKeys, encryptedGroups, validGroups, emptyGroups)
}
}
}
}
public suspend fun exportAll(): List<SymmetricKey> {
return export(validOnly = false)
}
public suspend fun exportValid(): List<SymmetricKey> {
return export(validOnly = true)
}
public suspend fun analyse(): String {
val keys = exportValid()
val process = ProcessBuilder("ent")
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start()
DataOutputStream(BufferedOutputStream(process.outputStream)).use { out ->
for (key in keys) {
out.writeInt(key.k0)
out.writeInt(key.k1)
out.writeInt(key.k2)
out.writeInt(key.k3)
}
}
val analysis = process.inputStream.readAllBytes().toString(Charsets.UTF_8)
val status = process.waitFor()
if (status != 0) {
throw Exception("ent failed: $status")
}
return analysis
}
private suspend fun export(validOnly: Boolean): List<SymmetricKey> {
return database.execute { connection ->
val query = if (validOnly) {
EXPORT_VALID_QUERY
} else {
EXPORT_ALL_QUERY
}
connection.prepareStatement(query).use { stmt ->
stmt.executeQuery().use { rows ->
val keys = mutableListOf<SymmetricKey>()
while (rows.next()) {
val k0 = rows.getInt(1)
val k1 = rows.getInt(2)
val k2 = rows.getInt(3)
val k3 = rows.getInt(4)
keys += SymmetricKey(k0, k1, k2, k3)
}
keys
}
}
}
}
private companion object {
private val EXPORT_ALL_QUERY = """
SELECT (k.key).k0, (k.key).k1, (k.key).k2, (k.key).k3
FROM keys k
ORDER BY k.id ASC
""".trimIndent()
private val EXPORT_VALID_QUERY = """
SELECT DISTINCT (k.key).k0, (k.key).k1, (k.key).k2, (k.key).k3, k.id
FROM keys k
JOIN containers c ON c.key_id = k.id
ORDER BY k.id ASC
""".trimIndent()
}
}