KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaMessageHandlerComponent.kt
2024-05-03 16:52:00 +07:00

62 lines
2.0 KiB
Kotlin

package ru.dbotthepony.kstarbound.lua
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonNull
import org.apache.logging.log4j.LogManager
import org.classdump.luna.ByteString
import org.classdump.luna.exec.CallPausedException
import org.classdump.luna.runtime.LuaFunction
import ru.dbotthepony.kommons.util.Either
import ru.dbotthepony.kstarbound.util.ActionPacer
import ru.dbotthepony.kstarbound.util.sbIntern
import ru.dbotthepony.kstarbound.world.World
class LuaMessageHandlerComponent(val lua: LuaEnvironment, val nameProvider: () -> String) {
private val handlers = HashMap<String, LuaFunction<*, *, *, *, *>>()
init {
val table = lua.newTable()
lua.globals["message"] = table
table["setHandler"] = luaFunction { message: ByteString, handler: LuaFunction<*, *, *, *, *>? ->
if (handler == null) {
handlers.remove(message.decode())
} else {
handlers[message.decode().sbIntern()] = handler
}
}
}
private val logPacer = ActionPacer(1, 5)
fun handle(message: String, isLocal: Boolean, arguments: JsonArray): JsonElement {
val handler = handlers[message] ?: throw World.MessageCallException("No registered handler for $message")
try {
val unpack = arguments.map { lua.from(it) }.toTypedArray()
val result = lua.executor.call(lua, handler, isLocal, *unpack)
if (result.isEmpty()) {
return JsonNull.INSTANCE
} else {
return toJsonFromLua(result[0])
}
} catch (err: CallPausedException) {
if (logPacer.consumeAndReturnDeadline() <= 0L)
LOGGER.error("${nameProvider.invoke()}: '$message' handler attempted to yield across C boundary", err)
throw World.MessageCallException("$message handler attempted to yield across C boundary")
} catch (err: Throwable) {
if (logPacer.consumeAndReturnDeadline() <= 0L)
LOGGER.error("${nameProvider.invoke()}: Exception while handling message '$message'", err)
throw err
}
}
companion object {
private val LOGGER = LogManager.getLogger()
}
}