blob: cee6904952e645d21e1961ad8c9e67ce1cb1b556 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
package moe.nea.firmament.apis
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 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()
}
}
}
private fun OptionalLong.orNull(): Long? {
if (this.isPresent)return null
return this.asLong
}
|