-
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ee6186b
commit f580896
Showing
11 changed files
with
186 additions
and
62 deletions.
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
cirno-serializable/src/main/kotlin/net/cakeyfox/serializable/data/ClusterStats.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package net.cakeyfox.serializable.data | ||
|
||
import kotlinx.serialization.SerialName | ||
import kotlinx.serialization.Serializable | ||
|
||
@Serializable | ||
data class ClusterStats( | ||
val serverCount: Int | ||
) { | ||
@Serializable | ||
data class TopggBotStats( | ||
@SerialName("server_count") | ||
val serverCount: Int | ||
) | ||
} |
10 changes: 0 additions & 10 deletions
10
cirno-serializable/src/main/kotlin/net/cakeyfox/serializable/data/TopggBotStats.kt
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 26 additions & 12 deletions
38
foxy/src/main/kotlin/net/cakeyfox/foxy/command/vanilla/utils/PingExecutor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,43 @@ | ||
package net.cakeyfox.foxy.command.vanilla.utils | ||
|
||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.withContext | ||
import net.cakeyfox.common.Colors | ||
import net.cakeyfox.common.FoxyEmotes | ||
import net.cakeyfox.foxy.command.FoxyInteractionContext | ||
import net.cakeyfox.foxy.command.structure.FoxyCommandExecutor | ||
import net.cakeyfox.foxy.utils.pretty | ||
import java.net.InetAddress | ||
|
||
class PingExecutor : FoxyCommandExecutor() { | ||
override suspend fun execute(context: FoxyInteractionContext) { | ||
val gatewayPing = context.jda.gatewayPing | ||
val currentShardId = context.jda.shardInfo.shardId + 1 | ||
val totalShards = context.jda.shardInfo.shardTotal | ||
val hostname = withContext(Dispatchers.IO) { | ||
InetAddress.getLocalHost().hostName | ||
} | ||
|
||
val response = pretty(FoxyEmotes.FoxyHowdy, "**Pong!**\n") + | ||
pretty(FoxyEmotes.FoxyWow, "**Gateway Ping:** `${gatewayPing}ms`\n") + | ||
pretty(FoxyEmotes.FoxyThink, "**Shard ID:** `${currentShardId}/${totalShards}`\n") + | ||
pretty(FoxyEmotes.FoxyCupcake, "**Cluster:** `$hostname`") | ||
val minClusterShards = context.foxy.currentCluster.minShard | ||
val maxClusterShards = context.foxy.currentCluster.maxShard | ||
|
||
context.reply { | ||
content = response | ||
embed { | ||
title = pretty(FoxyEmotes.FoxyWow, "Pong!") | ||
thumbnail = context.foxy.selfUser.effectiveAvatarUrl | ||
color = Colors.FOXY_DEFAULT | ||
|
||
field { | ||
name = pretty(FoxyEmotes.FoxyCupcake, "Gateway Ping:") | ||
value = "`${gatewayPing}ms`" | ||
inline = false | ||
} | ||
|
||
field { | ||
name = pretty(FoxyEmotes.FoxyThink, "Shard") | ||
value = "`${currentShardId}/${totalShards}`" | ||
inline = false | ||
} | ||
|
||
field { | ||
name = pretty(FoxyEmotes.FoxyDrinkingCoffee, "Cluster:") | ||
value = "`${context.foxy.currentCluster.name}` **(Shard ${minClusterShards}/${maxClusterShards})**" | ||
inline = false | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 106 additions & 11 deletions
117
foxy/src/main/kotlin/net/cakeyfox/foxy/utils/analytics/TopggStatsSender.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,137 @@ | ||
package net.cakeyfox.foxy.utils.analytics | ||
|
||
import io.ktor.client.* | ||
import io.ktor.client.request.* | ||
import io.ktor.client.statement.* | ||
import io.ktor.http.* | ||
import io.ktor.http.content.* | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.withContext | ||
import io.ktor.serialization.kotlinx.json.* | ||
import io.ktor.server.application.* | ||
import io.ktor.server.engine.* | ||
import io.ktor.server.netty.* | ||
import io.ktor.server.plugins.contentnegotiation.* | ||
import io.ktor.server.response.* | ||
import io.ktor.server.routing.* | ||
import kotlinx.coroutines.* | ||
import kotlinx.serialization.encodeToString | ||
import kotlinx.serialization.json.Json | ||
import kotlinx.serialization.json.buildJsonObject | ||
import kotlinx.serialization.json.put | ||
import mu.KotlinLogging | ||
import net.cakeyfox.foxy.FoxyInstance | ||
import net.cakeyfox.foxy.utils.analytics.utils.StatsSender | ||
import net.cakeyfox.serializable.data.TopggBotStats | ||
import net.cakeyfox.serializable.data.ClusterStats | ||
import kotlin.reflect.jvm.jvmName | ||
|
||
class TopggStatsSender( | ||
val foxy: FoxyInstance | ||
): StatsSender { | ||
) { | ||
private val logger = KotlinLogging.logger(this::class.jvmName) | ||
private val token = foxy.config.dblToken | ||
private val clientId = foxy.config.applicationId | ||
private val token = foxy.config.others.topggToken | ||
private val clientId = foxy.config.discord.applicationId | ||
private var statsSenderJob: Job? = null | ||
|
||
override suspend fun send(guildCount: Long): Boolean { | ||
init { | ||
if (foxy.currentCluster.canPublishStats && foxy.config.environment == "production") { | ||
startMainClusterRoutine() | ||
} else { | ||
startHttpServer() | ||
} | ||
} | ||
|
||
private fun startMainClusterRoutine() { | ||
logger.info { "Running TopggStatsSender on Main Cluster" } | ||
|
||
statsSenderJob = CoroutineScope(Dispatchers.IO).launch { | ||
while (true) { | ||
val serverCounts = getServerCountsFromClusters() | ||
sendStatsToTopGG(serverCounts) | ||
delay(3600000) | ||
} | ||
} | ||
} | ||
|
||
private suspend fun getServerCountsFromClusters(): Int { | ||
val client = HttpClient() | ||
val clusterUrls = foxy.config.discord.clusters | ||
.mapNotNull { if (!it.canPublishStats) it.clusterUrl else null } | ||
|
||
if (foxy.currentCluster.maxShard == 0 && foxy.currentCluster.minShard == 0) { | ||
return withContext(Dispatchers.IO) { | ||
foxy.shardManager.shards | ||
.map { it.awaitReady() } | ||
.sumOf { it.guilds.size } | ||
} | ||
} | ||
|
||
val otherClusterCounts = coroutineScope { | ||
clusterUrls.map { url -> | ||
async { | ||
try { | ||
val response = client.get(url) | ||
Json.decodeFromString<ClusterStats>(response.bodyAsText()).serverCount | ||
} catch (e: Exception) { | ||
logger.error(e) { "Failed to fetch server count from $url" } | ||
0 | ||
} | ||
} | ||
}.awaitAll() | ||
} | ||
|
||
val currentClusterCount = withContext(Dispatchers.IO) { | ||
foxy.shardManager.shards | ||
.map { it.awaitReady() } | ||
.sumOf { it.guilds.size } | ||
} | ||
|
||
logger.info { "Current cluster has $currentClusterCount servers." } | ||
|
||
val totalServerCount = currentClusterCount + otherClusterCounts.sum() | ||
logger.info { "Total server count: $totalServerCount" } | ||
|
||
return totalServerCount | ||
} | ||
|
||
private suspend fun sendStatsToTopGG(serverCount: Int): Boolean { | ||
return withContext(Dispatchers.IO) { | ||
val response = foxy.httpClient.post("https://top.gg/api/bots/$clientId/stats") { | ||
header("Authorization", token) | ||
accept(ContentType.Application.Json) | ||
setBody( | ||
TextContent(Json.encodeToString(TopggBotStats(guildCount)), ContentType.Application.Json) | ||
TextContent( | ||
Json.encodeToString(ClusterStats.TopggBotStats(serverCount)), | ||
ContentType.Application.Json | ||
) | ||
) | ||
} | ||
|
||
if (response.status != HttpStatusCode.OK) { | ||
logger.error { "Failed to send stats to top.gg: ${response.status}" } | ||
return@withContext false | ||
} | ||
|
||
logger.info { "Successfully sent stats to top.gg" } | ||
logger.info { "Sending $serverCount servers to Top.gg" } | ||
return@withContext true | ||
} | ||
} | ||
|
||
private fun startHttpServer() { | ||
embeddedServer(Netty, port = foxy.config.others.statsSenderPort) { | ||
install(ContentNegotiation) { | ||
json() | ||
} | ||
|
||
routing { | ||
get("/guilds") { | ||
val serverCount = foxy.shardManager.shards.sumOf { it.guilds.size } | ||
val response = buildJsonObject { | ||
put("serverCount", serverCount) | ||
} | ||
val jsonString = Json.encodeToString(response) | ||
call.respondText( | ||
contentType = ContentType.Application.Json, | ||
text = jsonString | ||
) | ||
} | ||
} | ||
}.start(wait = false) | ||
} | ||
} |
Oops, something went wrong.