Improve Performance

Signed-off-by: Chaoscaot <max@maxsp.de>
This commit is contained in:
2025-12-02 21:34:35 +01:00
parent 0a7a753c48
commit a089d42d9a
8 changed files with 45 additions and 60 deletions
@@ -20,12 +20,9 @@
package de.steamwar package de.steamwar
import de.steamwar.plugins.configurePlugins import de.steamwar.plugins.configurePlugins
import de.steamwar.routes.ResponseUser
import de.steamwar.routes.SchematicCode
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.engine.* import io.ktor.server.engine.*
import de.steamwar.routes.configureRoutes import de.steamwar.routes.configureRoutes
import de.steamwar.sql.SchematicType
import de.steamwar.sql.SteamwarUser import de.steamwar.sql.SteamwarUser
import io.ktor.server.netty.* import io.ktor.server.netty.*
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
@@ -47,7 +44,6 @@ fun main() {
Thread { Thread {
while (true) { while (true) {
Thread.sleep(1000 * 10) Thread.sleep(1000 * 10)
ResponseUser.clearCache()
SteamwarUser.clear() SteamwarUser.clear()
} }
}.start() }.start()
@@ -48,6 +48,7 @@ import java.time.Instant
fun Route.configureAuditLog() { fun Route.configureAuditLog() {
route("/auditlog") { route("/auditlog") {
install(SWPermissionCheck) { install(SWPermissionCheck) {
mustAuth = true
permission = UserPerm.MODERATION permission = UserPerm.MODERATION
} }
@@ -55,13 +56,13 @@ fun Route.configureAuditLog() {
val text = call.request.queryParameters["fullText"] val text = call.request.queryParameters["fullText"]
val actionText = call.request.queryParameters["actionText"] val actionText = call.request.queryParameters["actionText"]
val serverText = call.request.queryParameters["server"] val serverText = call.request.queryParameters["server"]
val actor = call.request.queryParameters.getAll("actor")?.toSet() val actor = call.request.queryParameters.getAll("actor")?.map { it.toInt() }?.toSet()
val actionType = val actionType =
call.request.queryParameters.getAll("actionType")?.map { AuditLog.Type.valueOf(it) }?.toSet() call.request.queryParameters.getAll("actionType")?.map { AuditLog.Type.valueOf(it) }?.toSet()
val timeGreater = call.request.queryParameters["timeGreater"]?.let { Instant.ofEpochMilli(it.toLong()) } val timeGreater = call.request.queryParameters["timeGreater"]?.let { Instant.ofEpochMilli(it.toLong()) }
val timeLess = call.request.queryParameters["timeLess"]?.let { Instant.ofEpochMilli(it.toLong()) } val timeLess = call.request.queryParameters["timeLess"]?.let { Instant.ofEpochMilli(it.toLong()) }
val serverOwner = call.request.queryParameters.getAll("serverOwner")?.toSet() val serverOwner = call.request.queryParameters.getAll("serverOwner")?.map { it.toInt() }?.toSet()
val velocity = call.request.queryParameters["velocity"]?.toBoolean() val velocity = call.request.queryParameters["velocity"]?.toBoolean()
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0 val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0
@@ -96,11 +97,11 @@ data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
actionText: String? = null, actionText: String? = null,
serverText: String? = null, serverText: String? = null,
fullText: String? = null, fullText: String? = null,
actor: Set<String>? = null, actor: Set<Int>? = null,
actionType: Set<AuditLog.Type>? = null, actionType: Set<AuditLog.Type>? = null,
timeGreater: Instant? = null, timeGreater: Instant? = null,
timeLess: Instant? = null, timeLess: Instant? = null,
serverOwner: Set<String>? = null, serverOwner: Set<Int>? = null,
velocity: Boolean? = null, velocity: Boolean? = null,
page: Int = 0, page: Int = 0,
limit: Int = 100, limit: Int = 100,
@@ -139,7 +140,7 @@ data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
query.andWhere { (AuditLogTable.actionText like "%$it%") or (AuditLogTable.server like "%$it%") } query.andWhere { (AuditLogTable.actionText like "%$it%") or (AuditLogTable.server like "%$it%") }
} }
actor?.let { query.andWhere { actorTable[SteamwarUserTable.uuid] inList actor } } actor?.let { query.andWhere { AuditLogTable.actor inList actor } }
actionType?.let { query.andWhere { AuditLogTable.action inList actionType } } actionType?.let { query.andWhere { AuditLogTable.action inList actionType } }
@@ -147,7 +148,7 @@ data class PagedAuditLog(val rows: Long, val entries: List<AuditLogEntry>) {
timeLess?.let { query.andWhere { AuditLogTable.time less timeLess } } timeLess?.let { query.andWhere { AuditLogTable.time less timeLess } }
serverOwner?.let { query.andWhere { serverOwnerTable[SteamwarUserTable.uuid] inList serverOwner } } serverOwner?.let { query.andWhere { AuditLogTable.serverOwner inList serverOwner } }
if (velocity == true) query.andWhere { AuditLogTable.serverOwner.isNull() } if (velocity == true) query.andWhere { AuditLogTable.serverOwner.isNull() }
@@ -66,7 +66,7 @@ fun Route.configureAuth() {
} }
call.sessions.set(SWUserSession(user.getId())) call.sessions.set(SWUserSession(user.getId()))
call.respond(ResponseUser.get(user)) call.respond(ResponseUser(user))
} }
delete { delete {
@@ -100,7 +100,7 @@ fun Route.configureAuth() {
} }
call.sessions.set(SWUserSession(user.getId())) call.sessions.set(SWUserSession(user.getId()))
call.respond(ResponseUser.get(user)) call.respond(ResponseUser(user))
} }
} }
} }
+11 -25
View File
@@ -44,28 +44,8 @@ import java.util.*
data class ResponseSchematicType(val name: String, val db: String) data class ResponseSchematicType(val name: String, val db: String)
@Serializable @Serializable
data class ResponseUser(val name: String, val uuid: String, val prefix: String, val perms: List<String>) { data class ResponseUser(val name: String, val uuid: String) {
private constructor(user: SteamwarUser) : this(user.userName, user.uuid.toString(), user.prefix().chatPrefix, user.perms().filter { !it.name.startsWith("PREFIX_") }.map { it.name }) constructor(user: SteamwarUser) : this(user.userName, user.uuid.toString())
companion object {
private val cache = mutableMapOf<Int, ResponseUser>()
fun get(id: Int): ResponseUser {
synchronized(cache) {
return cache[id] ?: ResponseUser(SteamwarUser.byId(id)!!).also { cache[id] = it }
}
}
fun get(user: SteamwarUser): ResponseUser = synchronized(cache) {
return cache[user.getId()] ?: ResponseUser(user).also { cache[user.getId()] = it }
}
fun clearCache() {
synchronized(cache) {
cache.clear()
}
}
}
} }
fun Route.configureDataRoutes() { fun Route.configureDataRoutes() {
@@ -76,7 +56,13 @@ fun Route.configureDataRoutes() {
permission = UserPerm.MODERATION permission = UserPerm.MODERATION
} }
get("/users") { get("/users") {
call.respond(useDb { SteamwarUser.all().map { ResponseUser.get(it) } }) val name = call.request.queryParameters["name"]
val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 100
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 0
val includePerms = call.request.queryParameters["includePerms"]?.toBoolean() ?: false
val includeId = call.request.queryParameters["includeId"]?.toBoolean() ?: false
} }
get("/teams") { get("/teams") {
call.respond(Team.getAll().map { ResponseTeam(it) }) call.respond(Team.getAll().map { ResponseTeam(it) })
@@ -119,7 +105,7 @@ fun Route.configureDataRoutes() {
listOf(UserPerm.PREFIX_ADMIN, UserPerm.PREFIX_DEVELOPER, UserPerm.PREFIX_MODERATOR, UserPerm.PREFIX_SUPPORTER, UserPerm.PREFIX_BUILDER) listOf(UserPerm.PREFIX_ADMIN, UserPerm.PREFIX_DEVELOPER, UserPerm.PREFIX_MODERATOR, UserPerm.PREFIX_SUPPORTER, UserPerm.PREFIX_BUILDER)
.associateWith { SteamwarUser.getUsersWithPerm(it) } .associateWith { SteamwarUser.getUsersWithPerm(it) }
.mapKeys { UserPerm.prefixes[it.key]!!.chatPrefix } .mapKeys { UserPerm.prefixes[it.key]!!.chatPrefix }
.mapValues { it.value.map { ResponseUser.get(it) } } .mapValues { it.value.map { ResponseUser(it) } }
) )
} }
get("/skin/{uuid}") { get("/skin/{uuid}") {
@@ -138,7 +124,7 @@ fun Route.configureDataRoutes() {
route("/me") { route("/me") {
install(SWPermissionCheck) install(SWPermissionCheck)
get { get {
call.respond(ResponseUser.get(call.principal<SWAuthPrincipal>()!!.user)) call.respond(ResponseUser(call.principal<SWAuthPrincipal>()!!.user))
} }
} }
} }
@@ -31,7 +31,7 @@ fun Route.configureEventRefereesRouting() {
route("/referees") { route("/referees") {
get { get {
val event = call.receiveEvent() ?: return@get val event = call.receiveEvent() ?: return@get
call.respond(Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) }) call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
} }
put { put {
val event = call.receiveEvent() ?: return@put val event = call.receiveEvent() ?: return@put
@@ -39,7 +39,7 @@ fun Route.configureEventRefereesRouting() {
referees.forEach { referees.forEach {
Referee.add(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId()) Referee.add(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
} }
call.respond(Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) }) call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
} }
delete { delete {
val event = call.receiveEvent() ?: return@delete val event = call.receiveEvent() ?: return@delete
@@ -47,7 +47,7 @@ fun Route.configureEventRefereesRouting() {
referees.forEach { referees.forEach {
Referee.remove(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId()) Referee.remove(event.eventID, SteamwarUser.get(UUID.fromString(it))!!.getId())
} }
call.respond(Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) }) call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) })
} }
} }
} }
@@ -118,7 +118,7 @@ data class ExtendedResponseEvent(
TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }, TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) },
EventGroup.get(event).map { ResponseGroups(it) }, EventGroup.get(event).map { ResponseGroups(it) },
EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }, EventFight.getEvent(event.eventID).map { ResponseEventFight(it) },
Referee.get(event.eventID).map { ResponseUser.get(SteamwarUser.byId(it)!!) }, Referee.get(event.eventID).map { ResponseUser(SteamwarUser.byId(it)!!) },
EventRelation.get(event).map { ResponseRelation(it) } EventRelation.get(event).map { ResponseRelation(it) }
) )
} }
@@ -34,9 +34,7 @@ import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.ByteArrayInputStream
import java.io.DataInputStream import java.io.DataInputStream
import java.io.InputStream
import java.security.MessageDigest import java.security.MessageDigest
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant
@@ -49,16 +47,6 @@ data class ResponseSchematic(val name: String, val id: Int, val type: String?, v
constructor(node: SchematicNode) : this(node.name, node.getId(), node.schemtype?.name(), node.owner, node.item, node.lastUpdate.time, node.rank, node.replaceColor(), node.allowReplay()) constructor(node: SchematicNode) : this(node.name, node.getId(), node.schemtype?.name(), node.owner, node.item, node.lastUpdate.time, node.rank, node.replaceColor(), node.allowReplay())
} }
@Serializable
data class ResponseSchematicLong(val members: List<ResponseUser>, val path: String, val schem: ResponseSchematic) {
constructor(node: SchematicNode, path: String): this(NodeMember.getNodeMembers(node.getId()).map { ResponseUser.get(it.member) }, path, ResponseSchematic(node))
}
@Serializable
data class ResponseSchematicList(val breadcrumbs: List<ResponseBreadcrumb>, val schematics: List<ResponseSchematic>, val players: Map<String, ResponseUser>) {
constructor(schematics: List<ResponseSchematic>, breadcrumbs: List<ResponseBreadcrumb>) : this(breadcrumbs, schematics, schematics.map { it.owner }.distinct().map { ResponseUser.get(it) }.associateBy { it.uuid })
}
@Serializable @Serializable
data class ResponseBreadcrumb(val name: String, val id: Int) data class ResponseBreadcrumb(val name: String, val id: Int)
@@ -23,11 +23,17 @@ import de.steamwar.plugins.SWPermissionCheck
import de.steamwar.plugins.getUser import de.steamwar.plugins.getUser
import de.steamwar.sql.SteamwarUser import de.steamwar.sql.SteamwarUser
import de.steamwar.sql.UserPerm import de.steamwar.sql.UserPerm
import io.ktor.http.* import io.ktor.http.HttpStatusCode
import io.ktor.server.application.* import io.ktor.server.application.ApplicationCall
import io.ktor.server.response.* import io.ktor.server.application.call
import io.ktor.server.routing.* import io.ktor.server.application.install
import kotlinx.serialization.Serializable import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.delete
import io.ktor.server.routing.get
import io.ktor.server.routing.put
import io.ktor.server.routing.route
import kotlinx.serialization.Serializable;
@Serializable @Serializable
data class RespondPrefix(val name: String, val colorCode: String, val chatPrefix: String) data class RespondPrefix(val name: String, val colorCode: String, val chatPrefix: String)
@@ -76,7 +82,12 @@ fun Route.configureUserPerms() {
val prefixs = UserPerm.prefixes[prefix]!! val prefixs = UserPerm.prefixes[prefix]!!
call.respond(RespondUserPermsPrefix(RespondPrefix(prefix.name, prefixs.colorCode, prefixs.chatPrefix), perms)) call.respond(
RespondUserPermsPrefix(
RespondPrefix(prefix.name, prefixs.colorCode, prefixs.chatPrefix),
perms
)
)
} }
put("/prefix/{prefix}") { put("/prefix/{prefix}") {
val (user, prefix) = call.receivePermission("prefix", isPrefix = true) ?: return@put val (user, prefix) = call.receivePermission("prefix", isPrefix = true) ?: return@put
@@ -112,7 +123,10 @@ fun Route.configureUserPerms() {
} }
} }
suspend fun ApplicationCall.receivePermission(fieldName: String = "perm", isPrefix: Boolean = false): Pair<SteamwarUser, UserPerm>? { suspend fun ApplicationCall.receivePermission(
fieldName: String = "perm",
isPrefix: Boolean = false
): Pair<SteamwarUser, UserPerm>? {
val user = request.getUser() val user = request.getUser()
if (user == null) { if (user == null) {
respond(HttpStatusCode.BadRequest) respond(HttpStatusCode.BadRequest)