ktorio / ktor

Framework for quickly creating connected applications in Kotlin with minimal effort
https://ktor.io
Apache License 2.0
12.72k stars 1.04k forks source link

JS - $this$ is undefined #1641

Open AthanaseKa opened 4 years ago

AthanaseKa commented 4 years ago

Hi,

I'm trying out ktor with coroutines in a multiplatform project. I'm building for Android, iOS and Javascript.

For the moment my code consists of a simple get call of an api. It works fine on Android and iOS, but I'm getting an $this$ is undefined when my javascript calls the same code.

My gradle dependencies:

implementation("org.jetbrains.kotlin:kotlin-stdlib-js")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.3")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:0.14.0")
implementation("io.ktor:ktor-client-js:1.3.1")
implementation("io.ktor:ktor-client-core-js:1.3.1")
implementation("io.ktor:ktor-client-json:1.3.1")
implementation("io.ktor:ktor-client-serialization-js:1.3.1")

Here are the multiplaform JS variations:

import kotlinx.coroutines.Dispatchers

actual val uiDispatcher: CoroutineContext
    get() = Dispatchers.Main

actual val defaultDispatcher: CoroutineContext
    get() = Dispatchers.Default
import io.ktor.client.engine.js.Js

actual object PlatformServiceLocator {
    actual val httpClientEngine: HttpClientEngine by lazy { Js.create() }
}

Thanks for the help

cy6erGn0m commented 4 years ago

Any stacktrace? Could you please show, how do you invoke get function?

AthanaseKa commented 4 years ago

@cy6erGn0m

Here is the code:

@ThreadLocal
object ServiceLocator {
    val sampleApi by lazy { SampleApi(PlatformServiceLocator.httpClientEngine) }
}

expect object PlatformServiceLocator {
    val httpClientEngine: HttpClientEngine
}

class SampleApi(clientEngine: HttpClientEngine) {

    private val client = HttpClient(clientEngine) {
        install(JsonFeature) {
            serializer = KotlinxSerializer()
        }
    }

    suspend fun getUser(id: Int): UserJson = client.get {
        val response = client.get<HttpResponse> {
            url {
                protocol = URLProtocol.HTTPS
                host = "api.sample.com"
                encodedPath = "/user/$id"
            }
        }
        val jsonBody = response.readText()
        return Json.nonstrict.parse(UserJson.serializer(), jsonBody)
    }
}

About the stack trace I get the $this$ is undefined on the javascript generated code.

AthanaseKa commented 4 years ago

This is a part of the generated js that fails:

function SampleApi$getUser$lambda(this$SampleApi, closure$id, closure$continuation) {
    return function ($receiver) {
      var $receiver_0 = this$SampleApi.client_0;
      var block = SampleApi$getUser$lambda$lambda(closure$id);
      var host;
      var body;
      host = 'localhost';
      body = utils.EmptyContent;
      var $receiver_1 = new HttpRequestBuilder_init();
      url($receiver_1, 'http', host, 0, '/');
      $receiver_1.method = HttpMethod.Companion.Get;
      $receiver_1.body = body;
      block($receiver_1);
      var $this_0 = new HttpStatement_init($receiver_1, $receiver_0);
      var tmp$_4, tmp$_5, tmp$_6;
      tmp$_4 = getKClass(HttpResponse);
      if (equals(tmp$_4, getKClass(HttpStatement_init))) {
        $this$.$result$ = Kotlin.isType(tmp$_5 = $this_0, HttpResponse) ? tmp$_5 : throwCCE();
      }
       else if (equals(tmp$_4, getKClass(HttpResponse))) {
        $this_0.execute($this$);
        $this$.$result$ = Kotlin.isType(tmp$_6 = $this$.$result$, HttpResponse) ? tmp$_6 : throwCCE();
      }

I get the error on $this_0.execute($this$);

AthanaseKa commented 4 years ago

After some digging, I found out that using client.get<String> { ... } works fine.

Now I know that HttpResponse has something wrong going on... Any idea ?

AthanaseKa commented 4 years ago

Actually found the problem, its the client.get inside the other client.get that is messing with the javascript generated code.

cy6erGn0m commented 4 years ago

@anton-bannykh cc

oleg-larshin commented 4 years ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.