From f2eb8c4dc898336f1ee44e62e18b4a7406464736 Mon Sep 17 00:00:00 2001 From: nea Date: Fri, 2 Jun 2023 23:01:09 +0200 Subject: Add more caching and fix some models --- src/main/kotlin/moe/nea/firmament/apis/Profiles.kt | 6 +- src/main/kotlin/moe/nea/firmament/apis/Routes.kt | 109 +++++++++++++++++++++ .../firmament/gui/profileviewer/ProfileViewer.kt | 54 +++------- 3 files changed, 128 insertions(+), 41 deletions(-) create mode 100644 src/main/kotlin/moe/nea/firmament/apis/Routes.kt (limited to 'src/main/kotlin/moe/nea') diff --git a/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt b/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt index 4fd5704..7132147 100644 --- a/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt +++ b/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt @@ -21,7 +21,7 @@ import moe.nea.firmament.util.json.InstantAsLongSerializer @Serializable data class Profiles( val success: Boolean, - val profiles: List + val profiles: List? ) @Serializable @@ -120,12 +120,12 @@ data class PlayerResponse( data class PlayerData( val uuid: UUID, val firstLogin: Instant, - val lastLogin: Instant, + val lastLogin: Instant? = null, @SerialName("playername") val playerName: String, val achievementsOneTime: List = listOf(), @SerialName("newPackageRank") - val packageRank: String?, + val packageRank: String? = null, val monthlyPackageRank: String? = null, val rankPlusColor: String = "GOLD" ) { diff --git a/src/main/kotlin/moe/nea/firmament/apis/Routes.kt b/src/main/kotlin/moe/nea/firmament/apis/Routes.kt new file mode 100644 index 0000000..7785d90 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/apis/Routes.kt @@ -0,0 +1,109 @@ +package moe.nea.firmament.apis + +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.client.request.parameter +import io.ktor.http.URLProtocol +import io.ktor.http.isSuccess +import io.ktor.http.path +import io.ktor.util.CaseInsensitiveMap +import java.util.UUID +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import moe.nea.firmament.Firmament +import moe.nea.firmament.util.MinecraftDispatcher + +object Routes { + val apiKey = "e721a103-96e0-400f-af2a-73b2a91007b1" + private val nameToUUID: MutableMap> = CaseInsensitiveMap() + private val profiles: MutableMap> = mutableMapOf() + private val accounts: MutableMap> = mutableMapOf() + private val UUIDToName: MutableMap> = mutableMapOf() + + suspend fun getPlayerNameForUUID(uuid: UUID): String? { + return withContext(MinecraftDispatcher) { + UUIDToName.computeIfAbsent(uuid) { + async(Firmament.coroutineScope.coroutineContext) { + val response = Firmament.httpClient.get("https://api.ashcon.app/mojang/v2/user/$uuid") + if (!response.status.isSuccess()) return@async null + val data = response.body() + launch(MinecraftDispatcher) { + nameToUUID[data.username] = async { data.uuid } + } + data.username + } + } + }.await() + } + + suspend fun getUUIDForPlayerName(name: String): UUID? { + return withContext(MinecraftDispatcher) { + nameToUUID.computeIfAbsent(name) { + async(Firmament.coroutineScope.coroutineContext) { + val response = Firmament.httpClient.get("https://api.ashcon.app/mojang/v2/user/$name") + if (!response.status.isSuccess()) return@async null + val data = response.body() + launch(MinecraftDispatcher) { + UUIDToName[data.uuid] = async { data.username } + } + data.uuid + } + } + }.await() + } + + suspend fun getAccountData(uuid: UUID): PlayerData? { + return withContext(MinecraftDispatcher) { + accounts.computeIfAbsent(uuid) { + async(Firmament.coroutineScope.coroutineContext) { + val response = Firmament.httpClient.get { + url { + protocol = URLProtocol.HTTPS + host = "api.hypixel.net" + path("player") + parameter("key", apiKey) + parameter("uuid", uuid) + } + } + if (!response.status.isSuccess()) { + launch(MinecraftDispatcher) { + @Suppress("DeferredResultUnused") + accounts.remove(uuid) + } + return@async null + } + response.body().player + } + } + }.await() + } + + suspend fun getProfiles(uuid: UUID): Profiles? { + return withContext(MinecraftDispatcher) { + profiles.computeIfAbsent(uuid) { + async(Firmament.coroutineScope.coroutineContext) { + val response = Firmament.httpClient.get { + url { + protocol = URLProtocol.HTTPS + host = "api.hypixel.net" + path("skyblock", "profiles") + parameter("key", apiKey) + parameter("uuid", uuid) + } + } + if (!response.status.isSuccess()) { + launch(MinecraftDispatcher) { + @Suppress("DeferredResultUnused") + profiles.remove(uuid) + } + return@async null + } + response.body() + } + } + }.await() + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/profileviewer/ProfileViewer.kt b/src/main/kotlin/moe/nea/firmament/gui/profileviewer/ProfileViewer.kt index 63cb5a8..98e9489 100644 --- a/src/main/kotlin/moe/nea/firmament/gui/profileviewer/ProfileViewer.kt +++ b/src/main/kotlin/moe/nea/firmament/gui/profileviewer/ProfileViewer.kt @@ -3,22 +3,15 @@ package moe.nea.firmament.gui.profileviewer import io.github.cottonmc.cotton.gui.client.CottonClientScreen import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription import io.github.cottonmc.cotton.gui.widget.WTabPanel -import io.ktor.client.call.body -import io.ktor.client.request.get -import io.ktor.client.request.parameter -import io.ktor.http.URLProtocol -import io.ktor.http.path import java.util.UUID import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource import kotlinx.coroutines.launch import net.minecraft.text.Text import moe.nea.firmament.Firmament -import moe.nea.firmament.apis.AshconNameLookup import moe.nea.firmament.apis.Member import moe.nea.firmament.apis.PlayerData -import moe.nea.firmament.apis.PlayerResponse import moe.nea.firmament.apis.Profile -import moe.nea.firmament.apis.Profiles +import moe.nea.firmament.apis.Routes import moe.nea.firmament.util.ScreenUtil class ProfileViewer( @@ -48,40 +41,25 @@ class ProfileViewer( fun onCommand(source: FabricClientCommandSource, name: String) { source.sendFeedback(Text.translatable("firmament.pv.lookingup", name)) Firmament.coroutineScope.launch { - val nameData = Firmament.httpClient.get("https://api.ashcon.app/mojang/v2/user/$name").body() - val names = mapOf(nameData.uuid to nameData.username) - val data = Firmament.httpClient.get { - url { - protocol = URLProtocol.HTTPS - host = "api.hypixel.net" - path("player") - parameter("key", "e721a103-96e0-400f-af2a-73b2a91007b1") - parameter("uuid", nameData.uuid) - } - }.body() - val accountData = mapOf(data.player.uuid to data.player) - val playerUuid = data.player.uuid - val profiles = Firmament.httpClient.get { - url { - protocol = URLProtocol.HTTPS - host = "api.hypixel.net" - path("skyblock", "profiles") - parameter("key", "e721a103-96e0-400f-af2a-73b2a91007b1") - parameter("uuid", playerUuid) - } - }.body() - val profile = profiles.profiles.find { it.selected } + val uuid = Routes.getUUIDForPlayerName(name) + if (uuid == null) { + source.sendError(Text.translatable("firmament.pv.noplayer", name)) + return@launch + } + val names = mapOf(uuid to (Routes.getPlayerNameForUUID(uuid) ?: name)) + val data = Routes.getAccountData(uuid) + if (data == null) { + source.sendError(Text.translatable("firmament.pv.nohypixel", name)) + return@launch + } + val accountData = mapOf(data.uuid to data) + val profiles = Routes.getProfiles(uuid) + val profile = profiles?.profiles?.find { it.selected } if (profile == null) { source.sendFeedback(Text.translatable("firmament.pv.noprofile", name)) return@launch } - ScreenUtil.setScreenLater( - CottonClientScreen( - ProfileViewer( - playerUuid, names, accountData, profile - ) - ) - ) + ScreenUtil.setScreenLater(CottonClientScreen(ProfileViewer(uuid, names, accountData, profile))) } } } -- cgit