Skip to content

Instantly share code, notes, and snippets.

@Proximyst
Created May 17, 2019 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Proximyst/1883d35bed861f3d93a3c0b997088521 to your computer and use it in GitHub Desktop.
Save Proximyst/1883d35bed861f3d93a3c0b997088521 to your computer and use it in GitHub Desktop.
overengineered events for discord4j lol
package com.proximyst.eisaku.eventhandling.framework
import com.proximyst.eisaku.Main
import discord4j.core.event.domain.Event
import kotlin.reflect.KClass
import kotlin.reflect.full.companionObject
object EventHandler {
val handlers = mutableListOf<EventHandlerClassWrapper<*>>()
fun fireEvent(event: Event) {
handlers
.mapNotNull { it.listeners[event.javaClass.kotlin] }
.flatten()
.forEach { it(event) }
}
fun <T : Any> register(companion: KClass<out EventHandlerClass<T>>, instance: T) {
if (!companion.isCompanion) {
throw IllegalArgumentException("A companion was not given where one is required")
}
val owner = companion.java.enclosingClass.kotlin
// Good measure, right?
if (owner.companionObject != companion) {
throw IllegalStateException()
}
handlers.add(EventHandlerClassWrapper(owner, instance))
}
inline fun <reified T : EventHandlerClass<O>, O : Any> register(instance: O) =
register(T::class, instance)
class DiscordEventListener<T : Event> {
private fun subscriber(event: T) {
fireEvent(event)
}
private fun register(kclass: KClass<T>) {
if (listeners.add(this)) {
Main.discordClient.eventDispatcher
.on(kclass.java)
.subscribe { subscriber(it) }
}
}
companion object {
private val listeners = mutableSetOf<DiscordEventListener<*>>()
internal fun <T : Event> handleEventType(kclass: KClass<T>) {
DiscordEventListener<T>().register(kclass)
}
}
}
}
package com.proximyst.eisaku.eventhandling.framework
interface EventHandlerClass<T: Any>
package com.proximyst.eisaku.eventhandling.framework
import discord4j.core.event.domain.Event
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.full.declaredMemberFunctions
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.valueParameters
class EventHandlerClassWrapper<T: Any>(
val kclass: KClass<*>,
val instance: T
) {
val listeners by lazy {
val map = mutableMapOf<KClass<out Event>, MutableList<EventListenerWrapper<T>>>()
.withDefault { mutableListOf() }
for (func in kclass.declaredMemberFunctions) {
if (func.findAnnotation<EventListener>() == null
|| func.returnType.classifier != Unit::class
) {
continue
}
val eventType = func.valueParameters.firstOrNull()
?.type?.classifier as? KClass<out Event>
?: continue
map[eventType] = map[eventType]!!.also {
it.add(
EventListenerWrapper(
func as KFunction<Unit>, eventType, instance
)
)
}
}
map.keys.forEach { EventHandler.DiscordEventListener.handleEventType(it) }
map
}
}
package com.proximyst.eisaku.eventhandling.framework
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class EventListener
package com.proximyst.eisaku.eventhandling.framework
import discord4j.core.event.domain.Event
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.full.callSuspend
class EventListenerWrapper<T: Any>(
val method: KFunction<Unit>,
val eventType: KClass<out Event>,
val instance: T
) {
operator fun invoke(event: Event) {
if (!eventType.java.isInstance(event)) {
return
}
if (method.isSuspend) {
GlobalScope.launch {
method.callSuspend(instance, event)
}
} else {
method.call(instance, event)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment