diff options
Diffstat (limited to 'src/main/kotlin/apis/UrsaManager.kt')
| -rw-r--r-- | src/main/kotlin/apis/UrsaManager.kt | 124 |
1 files changed, 65 insertions, 59 deletions
diff --git a/src/main/kotlin/apis/UrsaManager.kt b/src/main/kotlin/apis/UrsaManager.kt index 19e030c..cee6904 100644 --- a/src/main/kotlin/apis/UrsaManager.kt +++ b/src/main/kotlin/apis/UrsaManager.kt @@ -1,74 +1,80 @@ - - package moe.nea.firmament.apis -import io.ktor.client.request.get -import io.ktor.client.request.header -import io.ktor.client.statement.HttpResponse -import io.ktor.client.statement.bodyAsText -import io.ktor.http.appendPathSegments +import java.net.URI +import java.net.http.HttpResponse import java.time.Duration import java.time.Instant +import java.util.OptionalLong import java.util.UUID import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.withContext +import kotlinx.serialization.DeserializationStrategy +import kotlin.jvm.optionals.getOrNull import net.minecraft.client.MinecraftClient import moe.nea.firmament.Firmament +import moe.nea.firmament.util.net.HttpUtil object UrsaManager { - private data class Token( - val validUntil: Instant, - val token: String, - val obtainedFrom: String, - ) { - fun isValid(host: String) = Instant.now().plusSeconds(60) < validUntil && obtainedFrom == host - } + private data class Token( + val validUntil: Instant, + val token: String, + val obtainedFrom: String, + ) { + fun isValid(host: String) = Instant.now().plusSeconds(60) < validUntil && obtainedFrom == host + } - private var currentToken: Token? = null - private val lock = Mutex() - private fun getToken(host: String) = currentToken?.takeIf { it.isValid(host) } + private var currentToken: Token? = null + private val lock = Mutex() + private fun getToken(host: String) = currentToken?.takeIf { it.isValid(host) } + + suspend fun <T> request(path: List<String>, bodyHandler: HttpResponse.BodyHandler<T>): T { + var didLock = false + try { + val host = "ursa.notenoughupdates.org" + var token = getToken(host) + if (token == null) { + lock.lock() + didLock = true + token = getToken(host) + } + var url = URI.create("https://$host") + for (segment in path) { + url = url.resolve(segment) + } + val request = HttpUtil.request(url) + if (token == null) { + withContext(Dispatchers.IO) { + val mc = MinecraftClient.getInstance() + val serverId = UUID.randomUUID().toString() + mc.sessionService.joinServer(mc.session.uuidOrNull, mc.session.accessToken, serverId) + request.header("x-ursa-username", mc.session.username) + request.header("x-ursa-serverid", serverId) + } + } else { + request.header("x-ursa-token", token.token) + } + val response = request.execute(bodyHandler) + .await() + val savedToken = response.headers().firstValue("x-ursa-token").getOrNull() + if (savedToken != null) { + val validUntil = response.headers().firstValueAsLong("x-ursa-expires").orNull()?.let { Instant.ofEpochMilli(it) } + ?: (Instant.now() + Duration.ofMinutes(55)) + currentToken = Token(validUntil, savedToken, host) + } + if (response.statusCode() != 200) { + Firmament.logger.error("Failed to contact ursa minor: ${response.statusCode()}") + } + return response.body() + } finally { + if (didLock) + lock.unlock() + } + } +} - suspend fun request(path: List<String>): HttpResponse { - var didLock = false - try { - val host = "ursa.notenoughupdates.org" - var token = getToken(host) - if (token == null) { - lock.lock() - didLock = true - token = getToken(host) - } - val response = Firmament.httpClient.get { - url { - this.host = host - appendPathSegments(path, encodeSlash = true) - } - if (token == null) { - withContext(Dispatchers.IO) { - val mc = MinecraftClient.getInstance() - val serverId = UUID.randomUUID().toString() - mc.sessionService.joinServer(mc.session.uuidOrNull, mc.session.accessToken, serverId) - header("x-ursa-username", mc.session.username) - header("x-ursa-serverid", serverId) - } - } else { - header("x-ursa-token", token.token) - } - } - val savedToken = response.headers["x-ursa-token"] - if (savedToken != null) { - val validUntil = response.headers["x-ursa-expires"]?.toLongOrNull()?.let { Instant.ofEpochMilli(it) } - ?: (Instant.now() + Duration.ofMinutes(55)) - currentToken = Token(validUntil, savedToken, host) - } - if (response.status.value != 200) { - Firmament.logger.error("Failed to contact ursa minor: ${response.bodyAsText()}") - } - return response - } finally { - if (didLock) - lock.unlock() - } - } +private fun OptionalLong.orNull(): Long? { + if (this.isPresent)return null + return this.asLong } |
