
io.github.dszopa.message_router.MessageRouter.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of message-router Show documentation
Show all versions of message-router Show documentation
Improved Spark socket message handling, using frameworks like SocketIO for inspiration
package io.github.dszopa.message_router
import io.github.dszopa.message_router.annotation.Route
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult
import org.eclipse.jetty.websocket.api.Session
import org.json.JSONObject
import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.full.createInstance
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.jvm.jvmErasure
/**
* A router for socket messages
*
* This class will use reflection to find all functions annotated with
* "@Route" and will map the functions to their route values.
*
* @param packagePath the package to be scanned for routes.
* @constructor Creates a new message router with routes found
* through reflection.
*/
class MessageRouter(packagePath: String) {
private val routeToMethodCalls: HashMap>> = HashMap()
init {
val scanResult: ScanResult = FastClasspathScanner(packagePath)
.enableMethodAnnotationIndexing()
.scan()
val classesContainingRouteMethods: List = scanResult.getNamesOfClassesWithMethodAnnotation(Route::class.java)
for (className: String in classesContainingRouteMethods) {
val clazz: KClass<*> = Class.forName(className).kotlin
val instance: Any = clazz.createInstance()
for (function: KFunction<*> in clazz.declaredFunctions) {
if (function.annotations.any { it.annotationClass == Route::class}) {
if (!function.parameters.any { it.type.jvmErasure == String::class } ||
!function.parameters.any { it.type.jvmErasure == Session::class }) {
throw Error("Missing String and / or Session parameter types on function: ${function.name}")
}
val route: Route? = function.findAnnotation() // We already confirmed that it has a route annotation
if (route != null) {
val value: String = route.value
routeToMethodCalls.put(value, Pair(instance, function))
}
}
}
}
}
/**
* Routes incoming socket message to a function and calls that
* function with the given parameters.
* @param user A session object that indicates the user who sent the socket message.
* @param message The socket message, this must be in JSON format
* and include a "route" value in order for routing to work.
*/
fun handle(user: Session, message: String) {
val messageJson: JSONObject = JSONObject(message)
if (messageJson.has("route") && routeToMethodCalls.containsKey(messageJson.getString("route"))) {
val route: String = messageJson.getString("route")
val methodPair: Pair>? = routeToMethodCalls[route]
methodPair?.second?.call(methodPair.first, user, message)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy