Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make MasterGateway an interface and provide DefaultMasterGateway #390

Merged
merged 3 commits into from
Sep 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/src/main/kotlin/Kord.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package dev.kord.core
import dev.kord.cache.api.DataCache
import dev.kord.common.annotation.DeprecatedSinceKord
import dev.kord.common.annotation.KordExperimental
import dev.kord.common.annotation.KordPreview
import dev.kord.common.annotation.KordUnsafe
import dev.kord.common.entity.DiscordShard
import dev.kord.common.entity.PresenceStatus
Expand All @@ -22,6 +21,7 @@ import dev.kord.core.exception.EntityNotFoundException
import dev.kord.core.exception.KordInitializationException
import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.handler.GatewayEventInterceptor
import dev.kord.core.gateway.start
import dev.kord.core.supplier.*
import dev.kord.gateway.Gateway
import dev.kord.gateway.builder.PresenceBuilder
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/kotlin/builder/kord/KordBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import dev.kord.core.cache.createView
import dev.kord.core.cache.registerKordData
import dev.kord.core.event.Event
import dev.kord.core.exception.KordInitializationException
import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.DefaultMasterGateway
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.gateway.DefaultGateway
import dev.kord.gateway.Gateway
Expand Down Expand Up @@ -245,7 +245,7 @@ class KordBuilder(val token: String) {
put(shard, gateways[index])
}
}
MasterGateway(gateways)
DefaultMasterGateway(gateways)
}

val self = getBotIdFromToken(token)
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/kotlin/builder/kord/KordRestOnlyBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import dev.kord.core.ClientResources
import dev.kord.core.Kord
import dev.kord.core.event.Event
import dev.kord.core.exception.KordInitializationException
import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.DefaultMasterGateway
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.gateway.Gateway
import dev.kord.gateway.Intents
Expand Down Expand Up @@ -75,7 +75,7 @@ class KordRestOnlyBuilder(val token: String) {
return Kord(
resources,
DataCache.none(),
MasterGateway(mapOf(0 to Gateway.none())),
DefaultMasterGateway(mapOf(0 to Gateway.none())),
rest,
selfId,
MutableSharedFlow(),
Expand Down
40 changes: 40 additions & 0 deletions core/src/main/kotlin/gateway/DefaultMasterGateway.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dev.kord.core.gateway

import dev.kord.gateway.*
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flattenMerge
import kotlinx.coroutines.flow.map
import kotlin.time.Duration

class DefaultMasterGateway(
override val gateways: Map<Int, Gateway>,
): MasterGateway {

/**
* Calculates the average [Gateway.ping] of all running [gateways].
*
* Gateways that return `null` are not counted into the average, if all [gateways]
* return `null` then this property will return `null` as well.
*/
override val averagePing
get(): Duration? {
val pings = gateways.values.mapNotNull { it.ping.value?.inWholeMicroseconds }
if (pings.isEmpty()) return null

return Duration.microseconds(pings.average())
}


@OptIn(FlowPreview::class)
override val events: Flow<ShardEvent> = gateways.entries.asFlow()
.map { (shard, gateway) -> gateway.events.map { ShardEvent(it, gateway, shard) } }
.flattenMerge(gateways.size.coerceAtLeast(1))


override fun toString(): String {
return "MasterGateway(gateways=$gateways)"
}

}
43 changes: 11 additions & 32 deletions core/src/main/kotlin/gateway/MasterGateway.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,27 @@ import dev.kord.gateway.*
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flattenMerge
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlin.time.Duration
import kotlin.time.microseconds

data class ShardEvent(val event: Event, val gateway: Gateway, val shard: Int)

class MasterGateway(
val gateways: Map<Int, Gateway>,
) {
interface MasterGateway {
val gateways: Map<Int, Gateway>

/**
* Calculates the average [Gateway.ping] of all running [gateways].
*
* Gateways that return `null` are not counted into the average, if all [gateways]
* return `null` then this property will return `null` as well.
*/
val averagePing
get(): Duration? {
val pings = gateways.values.mapNotNull { it.ping.value?.inWholeMicroseconds }
if (pings.isEmpty()) return null

return Duration.microseconds(pings.average())
}
val averagePing: Duration?


@OptIn(FlowPreview::class)
val events: Flow<ShardEvent> = gateways.entries.asFlow()
.map { (shard, gateway) -> gateway.events.map { ShardEvent(it, gateway, shard) } }
.flattenMerge(gateways.size.coerceAtLeast(1))
val events: Flow<ShardEvent>

/**
* Calls [Gateway.start] on each Gateway in [gateways], changing the [GatewayConfiguration.shard] for each Gateway.
*/
suspend fun start(configuration: GatewayConfiguration): Unit = coroutineScope {
suspend fun startWithConfig(configuration: GatewayConfiguration): Unit = coroutineScope {
gateways.entries.forEach { (shard, gateway) ->
val config = configuration.copy(shard = configuration.shard.copy(index = shard))
launch {
Expand All @@ -49,20 +33,15 @@ class MasterGateway(
}
}

suspend inline fun start(token: String, config: GatewayConfigurationBuilder.() -> Unit = {}) {
val builder = GatewayConfigurationBuilder(token)
builder.apply(config)
start(builder.build())
}

suspend fun sendAll(command: Command) = gateways.values.forEach { it.send(command) }

suspend fun detachAll() = gateways.values.forEach { it.detach() }

suspend fun stopAll() = gateways.values.forEach { it.stop() }

override fun toString(): String {
return "MasterGateway(gateways=$gateways)"
}

}

suspend inline fun MasterGateway.start(token: String, config: GatewayConfigurationBuilder.() -> Unit = {}) {
val builder = GatewayConfigurationBuilder(token)
builder.apply(config)
startWithConfig(builder.build())
}
10 changes: 5 additions & 5 deletions core/src/test/kotlin/gateway/MasterGatewayTest.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package gateway

import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.DefaultMasterGateway
import dev.kord.gateway.Command
import dev.kord.gateway.Event
import dev.kord.gateway.Gateway
Expand All @@ -14,7 +14,7 @@ import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.time.Duration

internal class MasterGatewayTest {
internal class DefaultMasterGatewayTest {

@Test
fun `Gateway takes ping of single child`(){
Expand All @@ -23,7 +23,7 @@ internal class MasterGatewayTest {

dummy.ping.value = ping

val gateway = MasterGateway(
val gateway = DefaultMasterGateway(
mapOf(0 to dummy)
)

Expand All @@ -40,7 +40,7 @@ internal class MasterGatewayTest {
dummy1.ping.value = ping1
dummy2.ping.value = ping2

val gateway = MasterGateway(
val gateway = DefaultMasterGateway(
mapOf(0 to dummy1, 1 to dummy2)
)

Expand All @@ -51,7 +51,7 @@ internal class MasterGatewayTest {
fun `Gateway returns null ping when no gateway pings`(){
val dummy = DummyGateway()

val gateway = MasterGateway(
val gateway = DefaultMasterGateway(
mapOf(0 to dummy)
)

Expand Down
4 changes: 2 additions & 2 deletions core/src/test/kotlin/live/AbstractLiveEntityTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import dev.kord.common.entity.Snowflake
import dev.kord.core.ClientResources
import dev.kord.core.Kord
import dev.kord.core.builder.kord.Shards
import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.DefaultMasterGateway
import dev.kord.core.live.AbstractLiveKordEntity
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.gateway.*
Expand Down Expand Up @@ -105,7 +105,7 @@ abstract class AbstractLiveEntityTest<LIVE : AbstractLiveKordEntity> {
return Kord(
resources = ClientResources("token", Snowflake(0u), Shards(1), HttpClient(), EntitySupplyStrategy.cache, Intents.none),
cache = DataCache.none(),
MasterGateway(mapOf(0 to gateway)),
DefaultMasterGateway(mapOf(0 to gateway)),
RestClient(KtorRequestHandler(token = "token")),
randomId(),
MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE),
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/kotlin/performance/KordEventDropTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import dev.kord.core.ClientResources
import dev.kord.core.Kord
import dev.kord.core.builder.kord.Shards
import dev.kord.core.event.guild.GuildCreateEvent
import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.DefaultMasterGateway
import dev.kord.core.on
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.gateway.*
Expand Down Expand Up @@ -49,7 +49,7 @@ class KordEventDropTest {
val kord = Kord(
resources = ClientResources("token", Snowflake(0u), Shards(1), HttpClient(), EntitySupplyStrategy.cache, Intents.none),
cache = DataCache.none(),
MasterGateway(mapOf(0 to SpammyGateway)),
DefaultMasterGateway(mapOf(0 to SpammyGateway)),
RestClient(KtorRequestHandler("token", clock = Clock.System)),
Snowflake("420"),
MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE),
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/kotlin/regression/CacheMissRegression.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import dev.kord.core.builder.kord.configure
import dev.kord.core.builder.kord.getBotIdFromToken
import dev.kord.core.cache.data.ChannelData
import dev.kord.core.cache.registerKordData
import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.DefaultMasterGateway
import dev.kord.core.supplier.EntitySupplyStrategy
import dev.kord.gateway.*
import dev.kord.rest.request.JsonRequest
Expand Down Expand Up @@ -131,7 +131,7 @@ class CacheMissingRegressions {
kord = Kord(
resources,
MapDataCache().also { it.registerKordData() },
MasterGateway(mapOf(0 to FakeGateway)),
DefaultMasterGateway(mapOf(0 to FakeGateway)),
RestClient(CrashingHandler(resources.httpClient)),
getBotIdFromToken(token),
MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE),
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/kotlin/supplier/CacheEntitySupplierTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import dev.kord.core.ClientResources
import dev.kord.core.Kord
import dev.kord.core.builder.kord.Shards
import dev.kord.core.cache.KordCacheBuilder
import dev.kord.core.gateway.MasterGateway
import dev.kord.core.gateway.DefaultMasterGateway
import dev.kord.gateway.Gateway
import dev.kord.gateway.Intents
import dev.kord.gateway.PrivilegedIntent
Expand All @@ -28,7 +28,7 @@ internal class CacheEntitySupplierTest {
val kord = Kord(
ClientResources("", Snowflake(0u), Shards(0), HttpClient(), EntitySupplyStrategy.cache, Intents.all),
KordCacheBuilder().build(),
MasterGateway(mapOf(0 to Gateway.none())),
DefaultMasterGateway(mapOf(0 to Gateway.none())),
RestClient(KtorRequestHandler("")),
Snowflake(0u),
MutableSharedFlow(),
Expand Down