forked from Cookies_Github_mirror/AquaDX
[+] Metrics (#95)
* Add actuator and micrometer * update * [-] Remove unused import * [O] Make code less verbose * format * refactor --------- Co-authored-by: Azalea <22280294+hykilpikonna@users.noreply.github.com>
This commit is contained in:
@@ -2,9 +2,11 @@ package icu.samnyan.aqua.sega.maimai2
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.utils.ApiException
|
||||
import icu.samnyan.aqua.net.utils.simpleDescribe
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.maimai2.handler.*
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
import icu.samnyan.aqua.spring.Metrics
|
||||
import io.ktor.client.request.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.http.ResponseEntity
|
||||
@@ -339,29 +341,42 @@ class Maimai2ServletController(
|
||||
|
||||
@API("/{api}")
|
||||
fun handle(@PathVariable api: String, @RequestBody request: Map<String, Any>): Any {
|
||||
try {
|
||||
logger.info("Mai2 < $api : ${request.toJson()}") // TODO: Optimize logging
|
||||
logger.info("Mai2 < $api : ${request.toJson()}") // TODO: Optimize logging
|
||||
if (api !in noopEndpoint && api !in staticEndpoint && !handlers.containsKey(api)) {
|
||||
logger.warn("Mai2 > $api not found")
|
||||
return """{"returnCode":1,"apiName":"com.sega.maimai2servlet.api.$api"}"""
|
||||
}
|
||||
|
||||
if (api in noopEndpoint) {
|
||||
logger.info("Mai2 > $api no-op")
|
||||
return """{"returnCode":1,"apiName":"com.sega.maimai2servlet.api.$api"}"""
|
||||
}
|
||||
// Only record the counter metrics if the API is known.
|
||||
Metrics.counter("aquadx_maimai2_api_call", "api" to api).increment()
|
||||
|
||||
if (api in staticEndpoint) {
|
||||
logger.info("Mai2 > $api static")
|
||||
return staticEndpoint[api]!!
|
||||
}
|
||||
if (api in noopEndpoint) {
|
||||
logger.info("Mai2 > $api no-op")
|
||||
return """{"returnCode":1,"apiName":"com.sega.maimai2servlet.api.$api"}"""
|
||||
}
|
||||
|
||||
return handlers[api]?.handle(request)?.let { if (it is String) it else it.toJson() }?.also {
|
||||
if (api !in setOf("GetUserItemApi", "GetGameEventApi"))
|
||||
logger.info("Mai2 > $api : $it")
|
||||
} ?: {
|
||||
logger.warn("Mai2 > $api not found")
|
||||
"""{"returnCode":1,"apiName":"com.sega.maimai2servlet.api.$api"}"""
|
||||
if (api in staticEndpoint) {
|
||||
logger.info("Mai2 > $api static")
|
||||
return staticEndpoint[api]!!
|
||||
}
|
||||
|
||||
return try {
|
||||
Metrics.timer("aquadx_maimai2_api_latency", "api" to api).recordCallable {
|
||||
handlers[api]!!.handle(request).let { if (it is String) it else it.toJson() }.also {
|
||||
if (api !in setOf("GetUserItemApi", "GetGameEventApi"))
|
||||
logger.info("Mai2 > $api : $it")
|
||||
}
|
||||
}
|
||||
} catch (e: ApiException) {
|
||||
// It's a bad practice to return 200 ok on error, but this is what maimai does so we have to follow
|
||||
return ResponseEntity.ok().body("""{"returnCode":0,"apiName":"com.sega.maimai2servlet.api.$api","message":"${e.message?.replace("\"", "\\\"")} - ${e.code}"}""")
|
||||
} catch (e: Exception) {
|
||||
Metrics.counter(
|
||||
"aquadx_maimai2_api_error",
|
||||
"api" to api, "error" to e.simpleDescribe()
|
||||
).increment()
|
||||
|
||||
if (e is ApiException) {
|
||||
// It's a bad practice to return 200 ok on error, but this is what maimai does so we have to follow
|
||||
return ResponseEntity.ok().body("""{"returnCode":0,"apiName":"com.sega.maimai2servlet.api.$api","message":"${e.message?.replace("\"", "\\\"")} - ${e.code}"}""")
|
||||
} else throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package icu.samnyan.aqua.sega.maimai2.handler
|
||||
|
||||
import ext.millis
|
||||
import icu.samnyan.aqua.sega.allnet.TokenChecker
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserDataRepo
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserPlaylogRepo
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.maimai2.model.request.UploadUserPlaylog
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserPlaylog
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper
|
||||
import icu.samnyan.aqua.spring.Metrics
|
||||
import org.springframework.scheduling.annotation.Scheduled
|
||||
import org.springframework.stereotype.Component
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
@@ -24,11 +26,23 @@ class UploadUserPlaylogHandler(
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val playBacklog = mutableMapOf<Long, MutableList<BacklogEntry>>()
|
||||
|
||||
val VALID_GAME_IDS = setOf("SDEZ", "SDGA", "SDGB")
|
||||
}
|
||||
|
||||
override fun handle(request: Map<String, Any>): String {
|
||||
val req = mapper.convert(request, UploadUserPlaylog::class.java)
|
||||
|
||||
val version = tryParseGameVersion(req.userPlaylog.version)
|
||||
if (version != null) {
|
||||
val session = TokenChecker.getCurrentSession()
|
||||
val gameId = if (session?.gameId in VALID_GAME_IDS) session!!.gameId else ""
|
||||
Metrics.counter(
|
||||
"aquadx_maimai2_playlog_game_version",
|
||||
"game_id" to gameId, "version" to version
|
||||
).increment()
|
||||
}
|
||||
|
||||
// Save if the user is registered
|
||||
val u = userDataRepository.findByCardExtId(req.userId).getOrNull()
|
||||
if (u != null) playlogRepo.save(req.userPlaylog.apply { user = u })
|
||||
@@ -52,4 +66,13 @@ class UploadUserPlaylogHandler(
|
||||
playBacklog.filter { (_, v) -> v.isEmpty() || v[0].time - now > 300_000 }.toList()
|
||||
.forEach { (k, _) -> playBacklog.remove(k) }
|
||||
}
|
||||
|
||||
private fun tryParseGameVersion(version: Int): String? {
|
||||
val major = version / 1000000
|
||||
val minor = version / 1000 % 1000
|
||||
if (major != 1) return null
|
||||
if (minor !in 0..99) return null
|
||||
// e.g. "1.30", minor should have two digits
|
||||
return "$major.${minor.toString().padStart(2, '0')}"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user