Skip to content

Commit efbed9e

Browse files
authored
Merge pull request #524 from rfresh2/2b2t-vc-api
Seen, Playtime Commands + 2b2t queue API update
2 parents a2365a0 + e16d907 commit efbed9e

File tree

4 files changed

+136
-33
lines changed

4 files changed

+136
-33
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.lambda.client.command.commands
2+
3+
import com.google.gson.JsonParser
4+
import com.lambda.client.command.ClientCommand
5+
import com.lambda.client.commons.utils.ConnectionUtils
6+
import com.lambda.client.commons.utils.grammar
7+
import com.lambda.client.manager.managers.UUIDManager
8+
import com.lambda.client.util.text.MessageSendHelper
9+
import kotlin.time.DurationUnit
10+
import kotlin.time.toDuration
11+
12+
object PlaytimeCommand: ClientCommand(
13+
name = "playtime",
14+
alias = arrayOf("pt"),
15+
description = "Check a player's playtime on 2b2t"
16+
) {
17+
private val parser = JsonParser()
18+
19+
init {
20+
string("playerName") { playerName ->
21+
executeAsync("Check a player's playtime on 2b2t") {
22+
UUIDManager.getByName(playerName.value)?.let outer@ { profile ->
23+
ConnectionUtils.requestRawJsonFrom("https://api.2b2t.vc/playtime?uuid=${profile.uuid}") {
24+
MessageSendHelper.sendChatMessage("Failed querying playtime data for player: ${it.message}")
25+
}?.let {
26+
if (it.isEmpty()) {
27+
MessageSendHelper.sendChatMessage("No data found for player: ${profile.name}")
28+
return@outer
29+
}
30+
val jsonElement = parser.parse(it)
31+
val playtimeSeconds = jsonElement.asJsonObject["playtimeSeconds"].asDouble
32+
MessageSendHelper.sendChatMessage("${profile.name} has played for ${
33+
playtimeSeconds.toDuration(DurationUnit.SECONDS)
34+
}")
35+
}
36+
37+
return@executeAsync
38+
}
39+
40+
MessageSendHelper.sendChatMessage("Failed to find player with name ${playerName.value}")
41+
}
42+
}
43+
}
44+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.lambda.client.command.commands
2+
3+
import com.google.gson.JsonParser
4+
import com.lambda.client.command.ClientCommand
5+
import com.lambda.client.commons.utils.ConnectionUtils
6+
import com.lambda.client.manager.managers.UUIDManager
7+
import com.lambda.client.util.text.MessageSendHelper
8+
import java.time.ZoneId
9+
import java.time.ZonedDateTime
10+
import java.time.format.DateTimeFormatter
11+
12+
object SeenCommand : ClientCommand(
13+
name = "seen",
14+
alias = arrayOf("lastseen"),
15+
description = "Check when a player was last seen"
16+
) {
17+
18+
private val parser = JsonParser()
19+
20+
init {
21+
string("playerName") { playerName ->
22+
executeAsync("Check when a player was last seen") {
23+
UUIDManager.getByName(playerName.value)?.let outer@ { profile ->
24+
ConnectionUtils.requestRawJsonFrom("https://api.2b2t.vc/seen?uuid=${profile.uuid}") {
25+
MessageSendHelper.sendChatMessage("Failed querying seen data for player: ${it.message}")
26+
}?.let {
27+
if (it.isEmpty()) {
28+
MessageSendHelper.sendChatMessage("No data found for player: ${profile.name}")
29+
return@outer
30+
}
31+
val jsonElement = parser.parse(it)
32+
val dateRaw = jsonElement.asJsonObject["time"].asString
33+
val parsedDate = ZonedDateTime.parse(dateRaw).withZoneSameInstant(ZoneId.systemDefault())
34+
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.LONG)
35+
MessageSendHelper.sendChatMessage("${profile.name} was last seen on ${parsedDate.format(dateFormatter)}")
36+
}
37+
38+
return@executeAsync
39+
}
40+
41+
MessageSendHelper.sendChatMessage("Failed to find player with name ${playerName.value}")
42+
}
43+
}
44+
}
45+
}

src/main/kotlin/com/lambda/client/commons/utils/ConnectionUtils.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
package com.lambda.client.commons.utils
22

33
import com.lambda.client.module.modules.client.Plugins
4+
import java.net.HttpURLConnection
45
import java.net.URL
5-
import javax.net.ssl.HttpsURLConnection
66

77
object ConnectionUtils {
88

99
fun requestRawJsonFrom(url: String, catch: (Exception) -> Unit = { it.printStackTrace() }): String? {
1010
return runConnection(url, { connection ->
11+
connection.setRequestProperty("User-Agent", "LambdaClient")
12+
connection.setRequestProperty("Connection", "close")
1113
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8")
1214
if (Plugins.token.isNotBlank()) connection.setRequestProperty("Authorization", "token ${Plugins.token}")
1315
connection.requestMethod = "GET"
1416
connection.inputStream.readBytes().toString(Charsets.UTF_8)
1517
}, catch)
1618
}
1719

18-
fun <T> runConnection(url: String, block: (HttpsURLConnection) -> T?, catch: (Exception) -> Unit = { it.printStackTrace() }): T? {
19-
(URL(url).openConnection() as HttpsURLConnection).run {
20+
fun <T> runConnection(url: String, block: (HttpURLConnection) -> T?, catch: (Exception) -> Unit = { it.printStackTrace() }): T? {
21+
(URL(url).openConnection() as HttpURLConnection).run {
2022
return try {
2123
doOutput = true
2224
doInput = true
@@ -29,5 +31,4 @@ object ConnectionUtils {
2931
}
3032
}
3133
}
32-
3334
}
Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
package com.lambda.client.gui.hudgui.elements.misc
22

33
import com.google.gson.Gson
4-
import com.google.gson.annotations.SerializedName
4+
import com.lambda.client.LambdaMod
5+
import com.lambda.client.commons.utils.ConnectionUtils
56
import com.lambda.client.commons.utils.grammar
67
import com.lambda.client.event.SafeClientEvent
78
import com.lambda.client.gui.hudgui.LabelHud
89
import com.lambda.client.manager.managers.NetworkManager
910
import com.lambda.client.util.CachedValue
1011
import com.lambda.client.util.TickTimer
1112
import com.lambda.client.util.TimeUnit
12-
import com.lambda.client.util.WebUtils
1313
import com.lambda.client.util.text.MessageSendHelper
1414
import com.lambda.client.util.threads.defaultScope
1515
import kotlinx.coroutines.Dispatchers
1616
import kotlinx.coroutines.launch
17+
import java.time.Instant
18+
import java.time.ZonedDateTime
1719

1820
internal object Queue2B2T : LabelHud(
1921
name = "2B2T Queue",
@@ -22,22 +24,26 @@ internal object Queue2B2T : LabelHud(
2224
) {
2325
private val hasShownWarning = setting("Has Shown Warning", false, { false })
2426
private val show by setting("Show", Show.BOTH)
27+
private val showUpdatedTime by setting("Show Updated Time", true)
2528

2629
private enum class Show {
2730
BOTH, PRIORITY, REGULAR
2831
}
2932

30-
private const val apiUrl = "https://2bqueue.info/queue"
33+
private const val apiUrl = "https://api.2b2t.vc/queue"
3134

3235
private val gson = Gson()
3336
private val dataUpdateTimer = TickTimer(TimeUnit.SECONDS)
37+
private var hasInitialized = false
3438

35-
private var queueData = QueueData(0, 0, 0, 0)
39+
private var queueData = QueueData(0, 0, ZonedDateTime.now().toString())
3640
private val lastUpdate by CachedValue(1L, TimeUnit.SECONDS) {
37-
val difference = System.currentTimeMillis() - queueData.lastUpdated
41+
val dateRaw = queueData.time
42+
val parsedDate = ZonedDateTime.parse(dateRaw)
43+
val difference = Instant.now().epochSecond - parsedDate.toEpochSecond()
3844

39-
val minuteAmt = (difference / 60000L % 60L).toInt()
40-
val secondAmt = (difference / 1000L % 60L).toInt()
45+
val minuteAmt = (difference / 60L % 60L).toInt()
46+
val secondAmt = (difference % 60L).toInt()
4147
val minutes = grammar(minuteAmt, "minute", "minutes")
4248
val seconds = grammar(secondAmt, "second", "seconds")
4349

@@ -53,44 +59,54 @@ internal object Queue2B2T : LabelHud(
5359
sendWarning()
5460
}
5561

56-
if (dataUpdateTimer.tick(15L)) {
62+
if (dataUpdateTimer.tick(300L) // API caches queue data for 5 minutes
63+
|| !hasInitialized) {
64+
hasInitialized = true
5765
updateQueueData()
5866
}
5967

6068
if (NetworkManager.isOffline) {
61-
displayText.addLine("Cannot connect to 2bqueue.info", primaryColor)
69+
displayText.addLine("Cannot connect to api.2b2t.vc", primaryColor)
6270
displayText.add("Make sure your internet is working!", primaryColor)
63-
} else {
64-
if (showPriority) {
65-
displayText.add("Priority: ", primaryColor)
66-
displayText.add("${queueData.priority}", secondaryColor)
67-
}
71+
return
72+
}
6873

69-
if (showRegular) {
70-
displayText.add("Regular: ", primaryColor)
71-
displayText.add("${queueData.regular}", secondaryColor)
72-
}
74+
if (showPriority) {
75+
displayText.add("Priority: ", primaryColor)
76+
displayText.add("${queueData.prio}", secondaryColor)
77+
}
7378

79+
if (showRegular) {
80+
displayText.add("Regular: ", primaryColor)
81+
displayText.add("${queueData.regular}", secondaryColor)
82+
}
83+
if (showUpdatedTime) {
7484
displayText.addLine("", primaryColor)
7585
displayText.add("Last updated $lastUpdate ago", primaryColor)
7686
}
7787
}
7888

7989
private fun sendWarning() {
8090
MessageSendHelper.sendWarningMessage(
81-
"This module uses an external API, 2bqueue.info, which is operated by tycrek#0001." +
82-
"If you do not trust this external API / have not verified the safety yourself, disable this HUD component."
91+
"This module uses an external API, api.2b2t.vc, which is operated by rfresh#2222." +
92+
" If you do not trust this external API / have not verified the safety yourself, disable this HUD component."
8393
)
8494
hasShownWarning.value = true
8595
}
8696

8797
private fun updateQueueData() {
8898
defaultScope.launch(Dispatchers.IO) {
8999
runCatching {
90-
val json = WebUtils.getUrlContents(apiUrl)
91-
gson.fromJson(json, QueueData::class.java)
92-
}.getOrNull()?.let {
93-
queueData = it
100+
ConnectionUtils.requestRawJsonFrom(apiUrl) {
101+
LambdaMod.LOG.error("Failed querying queue data", it)
102+
}?.let {
103+
gson.fromJson(it, QueueData::class.java)?.let { data ->
104+
queueData = data
105+
return@runCatching
106+
}
107+
108+
LambdaMod.LOG.error("No queue data received. Is 2b2t down?")
109+
}
94110
}
95111
}
96112
}
@@ -99,11 +115,8 @@ internal object Queue2B2T : LabelHud(
99115
private val showRegular get() = show == Show.BOTH || show == Show.REGULAR
100116

101117
private class QueueData(
102-
@SerializedName("prio")
103-
val priority: Int,
118+
val prio: Int,
104119
val regular: Int,
105-
val total: Int,
106-
@SerializedName("timems")
107-
val lastUpdated: Long
120+
val time: String
108121
)
109122
}

0 commit comments

Comments
 (0)