본문 바로가기

프로그래밍 언어 노트/JAVA | Kotlin

[Ktor] + kts 활용해서 Dynamic Endpoint 만들기

Lee-WonJun/ktor-dynamic-endpoint-kts: Ktor-based server application sample that dynamically creates endpoints based on uploaded Kotlin script (.kts) files. (github.com)

 

GitHub - Lee-WonJun/ktor-dynamic-endpoint-kts: Ktor-based server application sample that dynamically creates endpoints based on

Ktor-based server application sample that dynamically creates endpoints based on uploaded Kotlin script (.kts) files. - GitHub - Lee-WonJun/ktor-dynamic-endpoint-kts: Ktor-based server application...

github.com

 

Kotlin 에서 Kotlin Script 라는게 존재하는데, 말그대로 Kotlin 인데 Script 인 녀석이다.

그리고 Ktor 같은 경우 DSL 을 통해서 route (endpoint) 를 구성하는데, 보통 이러면 동적으로 조작이 가능하다.  그게 서버에 반영이 되는지는 확인 해봐야 되는데 ktor 는 왠지 될것같은 느낌적 느낌.

 

근데 그러면

kotlin script 업로드해서 동적으로 endpoint 구성하고, 그 endpoint 에서 script 내용 고대로 실행 (eval) 하면 서버 실행중에도 endpoint 를 동적으로 추가 할수 있는거 아닌가?

라는 의문이 들었고, ktor 세팅해서 해봣는데

잘된다. 굳

 

구현도 아주 심플하다.

그냥 script 내용 고대로를 fns 맵에 저장하고, createDynamicEndpoint 로 route 에 해당 fn eval 하면 끝..

object DynamicRoute {
    private val fns : MutableMap<Pair<String, HttpMethod>, String> = mutableMapOf()

    private val body: suspend PipelineContext<Unit, ApplicationCall>.(Unit) -> Unit = {
        val scriptEngine = ScriptEngineManager().getEngineByExtension("kts")
        val result = scriptEngine.eval(fns[(call.request.path() to call.request.httpMethod)])
        call.respondText(result.toString())
    }

    fun addFunction(path: String, http: HttpMethod, script: String) {
        fns[path to http] = script
    }

    fun createDynamicEndpoint(routing: Routing, path: String, http: HttpMethod) {
        routing.children.firstOrNull{ it.selector.toString() == path }?.let {
            return
        }

        routing {
            when (http) {
                HttpMethod.Get -> get("/$path", body)
                HttpMethod.Post -> post("/$path", body)
                HttpMethod.Put -> put("/$path", body)
                HttpMethod.Delete -> delete("/$path", body)
                HttpMethod.Patch -> patch("/$path", body)
                HttpMethod.Options -> options("/$path", body)
                else -> throw IllegalArgumentException("Unsupported HTTP method")
            }
        }
    }
}

 

예시로

val greeting = "Hello, World!"
greeting

이런 기본적 script 부터

 

import dynamicEndpoint.objects.DynamicRoute

val x = try {
    val fnsfield = DynamicRoute::class.java.getDeclaredField("fns")
    fnsfield.toString()

    fnsfield.setAccessible(true);
    val fns = fnsfield.get(DynamicRoute)

    fns.toString()

} catch (e: Exception) {
    "Error: ${e.message}"
}

x

리플렉션으로 싱글턴 정보 가져오는것도 된다.

 

clojure 같은 LISP 계열 언어에서는 repl 로 접속해서 정보 보고 수정하고 이런게 가능한데, 무려 이런것도 된다

https://www.facebook.com/share/p/8nRGGcmfmfhPpL3v/

 

kotlin 은 어디까지 갈지 좀 파봐야 겠다.

728x90