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

feat/Job for live entity #285

Merged
merged 67 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
4243405
test: Begin test for LiveMessage
Distractic May 2, 2021
8e28ebe
test: Add tests for LiveMessage class
Distractic May 3, 2021
1c8c405
chore: Remove useless imports
Distractic May 3, 2021
6e42365
fix: shutdown action for live entity
Distractic May 4, 2021
1fe0e5f
fix: Cancel live entity when kord is cancel
Distractic May 4, 2021
e73dc58
Merge pull request #1 from Distractic/fix/shutdown_action_live_entity
Distractic May 4, 2021
4f2e896
Merge branch 'fix/live_entity_life_cycle' into test/live_entity
Distractic May 4, 2021
e41d2d6
fix: Resolve issue listening for onShutdown, chore: Refactor name shu…
Distractic May 4, 2021
99dfd36
test: Add abstract class to tests live entity
Distractic May 4, 2021
267575e
test: Add tests for abstract live entity and general behavior
Distractic May 4, 2021
82292e8
chore: Add generic type live entity in abstract class test
Distractic May 5, 2021
bee2dd4
chore: Deprecate onCreate method never called by entity
Distractic May 5, 2021
350d69d
test: Add tests for Member, Role and User live entity
Distractic May 5, 2021
c68974e
feat: Support BanAddEvent in live guild
Distractic May 5, 2021
7fdc816
test: Change test classes to simulate event and manage it
Distractic May 5, 2021
9ede98d
chore: Remove annotation need token bot
Distractic May 5, 2021
305dad6
chore: Adapt Role & User live test with send manual event
Distractic May 5, 2021
6b9f570
chore: Adapt Role & User live test with send manual event
Distractic May 5, 2021
ad5ccfe
test: Add check equality field of event, implements member live test
Distractic May 6, 2021
7361019
chore: Remove optIn no used
Distractic May 6, 2021
3d13743
fix: Correction tests to send fake event instead of real interaction
Distractic May 6, 2021
aaa94c0
test: Refactor test to build test with valid and random id
Distractic May 6, 2021
0ddf083
fix: Fix flow issue with delay ..
Distractic May 7, 2021
cda911d
fix: Rename package to resolve gradle issue
Distractic May 7, 2021
445b02a
test: Add Atomic counter to test event
Distractic May 8, 2021
cb66e45
test: End tests for guild live entity
Distractic May 8, 2021
2a76eb4
chore: Place deprecated annotation on live entity
Distractic May 8, 2021
71661d8
test: Live category test
Distractic May 9, 2021
f17bb71
chore: Use sequence random id from other tests
Distractic May 9, 2021
38b84de
test: Tests for all live entities category
Distractic May 9, 2021
144269d
test: Add Integrations update for guild live entity
Distractic May 11, 2021
eda09c0
fix: Add delay between creation job and send event
Distractic May 12, 2021
2b99aa0
chore: Add deprecated annotation on GuildCreateEvent for live channel
Distractic May 12, 2021
07e278b
fix: Use guild test channel type (according to GuildMessageChannel)
Distractic May 12, 2021
dc438c2
chore: format
Distractic May 12, 2021
15356f1
chore: change package name and function name
Distractic May 12, 2021
ab33a22
chore: Use randomID, refactor send event
Distractic May 12, 2021
04819cd
Merge pull request #2 from Distractic/test/live_entity
Distractic May 12, 2021
4b80450
chore: Doc about shutdown action
Distractic May 12, 2021
1757b45
chore: Change ReplaceWith in Deprecated annotation, rename shutdown m…
Distractic May 13, 2021
05ccd86
fix: Remove shutdown action property
Distractic May 13, 2021
2f42ea7
feat: Add cause of shut down live entity
Distractic May 13, 2021
fe70c9b
chore: Set deprecate level to Error
Distractic May 14, 2021
a20407f
test: Add test for LiveGuild with method onGuildCreate
Distractic May 14, 2021
3142059
chore: Rename method about completion of job
Distractic May 14, 2021
2ec9e38
feat: Add cancellation exception class for live entity
Distractic May 14, 2021
69fa448
feat: Add cause of cancellation to retrieve event for each live entity
Distractic May 14, 2021
b088a88
chore: format
Distractic May 14, 2021
bc4a24c
tests: Remove delay and use queue to manage action
Distractic May 15, 2021
a48cc6a
tests: Add tests for LiveCancellationException constructor
Distractic May 15, 2021
4d3f7be
chore: Refactor property of LiveCancellationException
Distractic May 15, 2021
35b8bd1
fix: Null pointer in live entities tests
Distractic May 15, 2021
a730fbe
chore: try to add delay in tests
Distractic May 15, 2021
ea0b2f4
chore: Create constante for delay time in tests
Distractic May 15, 2021
7adb7a7
chore: try old system for tests with CI
Distractic May 15, 2021
060f588
Merge remote-tracking branch 'origin/fix/shutdown_action_live_entity'…
Distractic May 15, 2021
445c4d3
fix: Remove non-existent code
Distractic May 15, 2021
f2c07ac
Retry github action
Distractic May 15, 2021
973a4af
tests: Check data event caused shutDown
Distractic May 15, 2021
0000500
Retry github action
Distractic May 16, 2021
8a88c2d
Retry github action
Distractic May 16, 2021
4392058
Retry github action
Distractic May 16, 2021
2e6321d
chore: Change sentence in deprecated annotation
Distractic May 16, 2021
6bfab84
chore: Remove replaceWith
Distractic May 16, 2021
10ac5da
chore: Homogenize cancel message
Distractic May 16, 2021
5557a64
chore: Fix imports and ReplaceWith for Deprecated annotation
Distractic May 17, 2021
3841ae9
chore: Remove ReplaceWith for forgotten Deprecated annotation
Distractic May 17, 2021
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/gateway/handler/GuildEventHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ internal class GuildEventHandler(
cache.put(data)
event.guild.cache()

coreFlow.emit(GuildCreateEvent(Guild(data, kord), shard))
coreFlow.emit(GuildUpdateEvent(Guild(data, kord), shard))
}

private suspend fun handle(event: GuildDelete, shard: Int) = with(event.guild) {
Expand Down
18 changes: 16 additions & 2 deletions core/src/main/kotlin/live/LiveGuild.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.kord.core.live

import dev.kord.common.annotation.KordPreview
import dev.kord.common.entity.Snowflake
import dev.kord.common.entity.optional.map
import dev.kord.core.entity.Guild
import dev.kord.core.entity.KordEntity
Expand All @@ -16,6 +17,7 @@ import dev.kord.core.event.role.RoleDeleteEvent
import dev.kord.core.event.role.RoleUpdateEvent
import dev.kord.core.event.user.PresenceUpdateEvent
import dev.kord.core.event.user.VoiceStateUpdateEvent
import dev.kord.core.live.exception.LiveCancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

Expand All @@ -33,6 +35,9 @@ fun LiveGuild.onEmojisUpdate(block: suspend (EmojisUpdateEvent) -> Unit) = on(co
@KordPreview
fun LiveGuild.onIntegrationsUpdate(block: suspend (IntegrationsUpdateEvent) -> Unit) = on(consumer = block)

@KordPreview
fun LiveGuild.onBanAdd(block: suspend (BanAddEvent) -> Unit) = on(consumer = block)

@KordPreview
fun LiveGuild.onBanRemove(block: suspend (BanRemoveEvent) -> Unit) = on(consumer = block)

Expand Down Expand Up @@ -119,14 +124,22 @@ fun LiveGuild.onGuildCreate(block: suspend (GuildCreateEvent) -> Unit) = on(cons
@KordPreview
fun LiveGuild.onGuildUpdate(block: suspend (GuildUpdateEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveGuild.onGuildDelete(block: suspend (GuildDeleteEvent) -> Unit) = on(consumer = block)

@KordPreview
class LiveGuild(
guild: Guild,
dispatcher: CoroutineDispatcher = Dispatchers.Default
) : AbstractLiveKordEntity(dispatcher), KordEntity by guild {
) : AbstractLiveKordEntity(guild.kord, dispatcher), KordEntity {

override val id: Snowflake
get() = guild.id

var guild: Guild = guild
private set
Expand All @@ -136,6 +149,7 @@ class LiveGuild(

is IntegrationsUpdateEvent -> event.guildId == guild.id

is BanAddEvent -> event.guildId == guild.id
is BanRemoveEvent -> event.guildId == guild.id

is PresenceUpdateEvent -> event.guildId == guild.id
Expand Down Expand Up @@ -206,7 +220,7 @@ class LiveGuild(
), kord)

is GuildUpdateEvent -> guild = event.guild
is GuildDeleteEvent -> shutDown()
is GuildDeleteEvent -> shutDown(LiveCancellationException(event, "The guild is deleted"))
else -> Unit
}

Expand Down
14 changes: 8 additions & 6 deletions core/src/main/kotlin/live/LiveKordEntity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ import kotlin.coroutines.CoroutineContext
interface LiveKordEntity : KordEntity, CoroutineScope {
val events: Flow<Event>

fun shutDown()
fun shutDown(cause: CancellationException = CancellationException("The live entity has been shut down", null))
}

@KordPreview
abstract class AbstractLiveKordEntity(dispatcher: CoroutineDispatcher) : LiveKordEntity {
abstract class AbstractLiveKordEntity(final override val kord: Kord, dispatcher: CoroutineDispatcher) : LiveKordEntity {

override val coroutineContext: CoroutineContext = dispatcher + SupervisorJob()
override val coroutineContext: CoroutineContext = dispatcher + SupervisorJob(kord.coroutineContext.job)

private val mutex = Mutex()

@Suppress("EXPERIMENTAL_API_USAGE")
override val events: Flow<Event>
final override val events: Flow<Event>
get() = kord.events
.takeWhile { isActive }
.filter { filter(it) }
Expand All @@ -44,9 +44,11 @@ abstract class AbstractLiveKordEntity(dispatcher: CoroutineDispatcher) : LiveKor
protected abstract fun filter(event: Event): Boolean
protected abstract fun update(event: Event)

override fun shutDown() {
cancel("Shutdown executed")
init {
events.launchIn(this)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a computed property, even if you launched the flow, consequent calls of the events property will create a new flow. Am I missing something? (I will edit this if I found out why)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand the issue here
The property has been declared as 'final' so that it is not overloaded
The use here of "launchIn" allows to listen to the events about the death of the entity
When using the events property, it allows to use the events of kord while applying a filter and a behavior.
In the current case, this makes it possible to create a flow which is filtered according to the data of the entity (id or others, see filter method) while applying a behavior (update), which here will be specifically the "shutDown" method

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a user will launch their own flow
Who is listening to the flow we launched in this code?
Final means it can't be overriden, but the field itself is still computed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an entity is to be able to observe its death (so it can cancel its scope), it has to listen to events. Under normal use this isn't a problem since a user will always listen to at least one event type, prompting the entity to process all events. This is here to cover the edge case where a user, for whatever reason, does not listen to any events but does want to observer the deletion of the entity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes the user will launch their own flow, BUT, when we use the method on<Event>{...}, we receive a Job.
The job can be cancelled, so the live entity no longer has children .. and in case where the live entity must be shut down (for LiveMessage, if the message is deleted for example), there is no more childrens to listen the death of the live entity.
So to resolve that, we listen the events from the beginning (without keep a reference to the job, because when the live entity is cancel, the job too), thus all jobs created and cancelled by the user, will always leave a alone job child to keep possibility to listen death events (GuildDelete, MessageDelete, etc.).

It's because we don't need to store the flow .. the method on will exploit the new flow computed and create a job.. So we need a new Flow each times

Copy link
Contributor Author

@Distractic Distractic May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parent (LiveEntity) needs at least one children (Job) to know his death and executes shut down (from update method)

}

override fun shutDown(cause: CancellationException) = cancel(cause)
}

/**
Expand Down
37 changes: 31 additions & 6 deletions core/src/main/kotlin/live/LiveMember.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.kord.core.live

import dev.kord.common.annotation.KordPreview
import dev.kord.common.entity.Snowflake
import dev.kord.core.entity.KordEntity
import dev.kord.core.entity.Member
import dev.kord.core.event.Event
Expand All @@ -9,6 +10,7 @@ import dev.kord.core.event.guild.GuildDeleteEvent
import dev.kord.core.event.guild.MemberLeaveEvent
import dev.kord.core.event.guild.MemberUpdateEvent
import dev.kord.core.live.channel.LiveGuildChannel
import dev.kord.core.live.exception.LiveCancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

Expand All @@ -19,30 +21,54 @@ fun Member.live(dispatcher: CoroutineDispatcher = Dispatchers.Default) = LiveMem
inline fun Member.live(dispatcher: CoroutineDispatcher = Dispatchers.Default, block: LiveMember.() -> Unit) =
this.live(dispatcher).apply(block)

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveMember.onLeave(block: suspend (MemberLeaveEvent) -> Unit) = on(consumer = block)

@KordPreview
fun LiveMember.onUpdate(block: suspend (MemberUpdateEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveMember.onBanAdd(block: suspend (BanAddEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
inline fun LiveGuildChannel.onShutDown(crossinline block: suspend (Event) -> Unit) = on<Event> {
inline fun LiveGuildChannel.onShutdown(crossinline block: suspend (Event) -> Unit) = on<Event> {
if (it is MemberLeaveEvent || it is BanAddEvent || it is GuildDeleteEvent) {
block(it)
}
}

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveGuildChannel.onGuildDelete(block: suspend (GuildDeleteEvent) -> Unit) = on(consumer = block)

@KordPreview
class LiveMember(
member: Member,
dispatcher: CoroutineDispatcher = Dispatchers.Default
) : AbstractLiveKordEntity(dispatcher), KordEntity by member {
) : AbstractLiveKordEntity(member.kord, dispatcher), KordEntity {

override val id: Snowflake
get() = member.id

var member = member
private set

Expand All @@ -52,13 +78,12 @@ class LiveMember(
is BanAddEvent -> member.id == event.user.id
is GuildDeleteEvent -> member.guildId == event.guildId
else -> false

}

override fun update(event: Event) = when (event) {
is MemberLeaveEvent -> shutDown()
is BanAddEvent -> shutDown()
is GuildDeleteEvent -> shutDown()
is MemberLeaveEvent -> shutDown(LiveCancellationException(event, "The member has left"))
is BanAddEvent -> shutDown(LiveCancellationException(event, "The member is banned"))
is GuildDeleteEvent -> shutDown(LiveCancellationException(event, "The guild is deleted"))
is MemberUpdateEvent -> member = event.member

else -> Unit
Expand Down
50 changes: 44 additions & 6 deletions core/src/main/kotlin/live/LiveMessage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import dev.kord.core.event.Event
import dev.kord.core.event.channel.ChannelDeleteEvent
import dev.kord.core.event.guild.GuildDeleteEvent
import dev.kord.core.event.message.*
import dev.kord.core.live.exception.LiveCancellationException
import dev.kord.core.supplier.EntitySupplyStrategy
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -53,30 +54,60 @@ inline fun LiveMessage.onReactionRemove(
@KordPreview
fun LiveMessage.onReactionRemoveAll(block: suspend (ReactionRemoveAllEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is never called because the message is already created",
ReplaceWith("LiveChannel.onMessageCreate(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveMessage.onCreate(block: suspend (MessageCreateEvent) -> Unit) = on(consumer = block)

@KordPreview
fun LiveMessage.onUpdate(block: suspend (MessageUpdateEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
inline fun LiveMessage.onShutDown(crossinline block: suspend (Event) -> Unit) = on<Event> {
inline fun LiveMessage.onShutdown(crossinline block: suspend (Event) -> Unit) = on<Event> {
if (it is MessageDeleteEvent || it is MessageBulkDeleteEvent
|| it is ChannelDeleteEvent || it is GuildDeleteEvent
) {
block(it)
}
}

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveMessage.onOnlyDelete(block: suspend (MessageDeleteEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveMessage.onBulkDelete(block: suspend (MessageBulkDeleteEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveMessage.onChannelDelete(block: suspend (ChannelDeleteEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveMessage.onGuildDelete(block: suspend (GuildDeleteEvent) -> Unit) = on(consumer = block)

Expand All @@ -85,7 +116,10 @@ class LiveMessage(
message: Message,
val guildId: Snowflake?,
dispatcher: CoroutineDispatcher = Dispatchers.Default
) : AbstractLiveKordEntity(dispatcher), KordEntity by message {
) : AbstractLiveKordEntity(message.kord, dispatcher), KordEntity {

override val id: Snowflake
get() = message.id

var message: Message = message
private set
Expand All @@ -112,12 +146,16 @@ class LiveMessage(
is ReactionRemoveAllEvent -> message = Message(message.data.copy(reactions = Optional.Missing()), kord)

is MessageUpdateEvent -> message = Message(message.data + event.new, kord)
is MessageDeleteEvent -> shutDown()
is MessageBulkDeleteEvent -> shutDown()
is MessageDeleteEvent, is MessageBulkDeleteEvent -> shutDown(
LiveCancellationException(
event,
"The message is deleted"
)
)

is ChannelDeleteEvent -> shutDown()
is ChannelDeleteEvent -> shutDown(LiveCancellationException(event, "The channel is deleted"))

is GuildDeleteEvent -> shutDown()
is GuildDeleteEvent -> shutDown(LiveCancellationException(event, "The guild is deleted"))
else -> Unit
}

Expand Down
29 changes: 25 additions & 4 deletions core/src/main/kotlin/live/LiveRole.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package dev.kord.core.live

import dev.kord.common.annotation.KordPreview
import dev.kord.common.entity.Snowflake
import dev.kord.core.entity.KordEntity
import dev.kord.core.entity.Role
import dev.kord.core.event.Event
import dev.kord.core.event.guild.GuildDeleteEvent
import dev.kord.core.event.role.RoleDeleteEvent
import dev.kord.core.event.role.RoleUpdateEvent
import dev.kord.core.live.exception.LiveCancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

Expand All @@ -17,27 +19,46 @@ fun Role.live(dispatcher: CoroutineDispatcher = Dispatchers.Default) = LiveRole(
inline fun Role.live(dispatcher: CoroutineDispatcher = Dispatchers.Default, block: LiveRole.() -> Unit) =
this.live(dispatcher).apply(block)

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveRole.onDelete(block: suspend (RoleDeleteEvent) -> Unit) = on(consumer = block)

@KordPreview
fun LiveRole.onUpdate(block: suspend (RoleUpdateEvent) -> Unit) = on(consumer = block)

@Deprecated(
"The block is not called when the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
inline fun LiveRole.onShutDown(crossinline block: suspend (Event) -> Unit) = on<Event> {
inline fun LiveRole.onShutdown(crossinline block: suspend (Event) -> Unit) = on<Event> {
if (it is RoleDeleteEvent || it is GuildDeleteEvent) {
block(it)
}
}

@Deprecated(
"The block is not called when the entity is deleted because the live entity is shutdown",
ReplaceWith("coroutineContext.job.invokeOnCompletion(block)"),
DeprecationLevel.ERROR
)
@KordPreview
fun LiveRole.onGuildDelete(block: suspend (GuildDeleteEvent) -> Unit) = on(consumer = block)

@KordPreview
class LiveRole(
role: Role,
dispatcher: CoroutineDispatcher = Dispatchers.Default
) : AbstractLiveKordEntity(dispatcher), KordEntity by role {
) : AbstractLiveKordEntity(role.kord, dispatcher), KordEntity {

override val id: Snowflake
get() = role.id

var role = role
private set

Expand All @@ -49,8 +70,8 @@ class LiveRole(
}

override fun update(event: Event) = when (event) {
is RoleDeleteEvent -> shutDown()
is GuildDeleteEvent -> shutDown()
is RoleDeleteEvent -> shutDown(LiveCancellationException(event, "The role is deleted"))
is GuildDeleteEvent -> shutDown(LiveCancellationException(event, "The guild is deleted"))
is RoleUpdateEvent -> role = event.role
else -> Unit
}
Expand Down
Loading