Skip to content

Instantly share code, notes, and snippets.

@Lochnair
Created February 13, 2025 04:32
Show Gist options
  • Select an option

  • Save Lochnair/db5a78ffd5444805e1031e75f1cfadf3 to your computer and use it in GitHub Desktop.

Select an option

Save Lochnair/db5a78ffd5444805e1031e75f1cfadf3 to your computer and use it in GitHub Desktop.

Revisions

  1. Lochnair created this gist Feb 13, 2025.
    70 changes: 70 additions & 0 deletions KtorZiplineHttpClient.kts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,70 @@
    package com.github.inkshelf.app

    import app.cash.zipline.loader.ZiplineHttpClient
    import io.ktor.client.HttpClient
    import io.ktor.client.call.body
    import io.ktor.client.plugins.websocket.webSocketSession
    import io.ktor.client.request.get
    import io.ktor.client.request.headers
    import io.ktor.client.statement.HttpResponse
    import io.ktor.client.statement.bodyAsBytes
    import io.ktor.http.isSuccess
    import io.ktor.utils.io.read
    import io.ktor.websocket.Frame
    import io.ktor.websocket.close
    import io.ktor.websocket.readText
    import kotlinx.coroutines.channels.trySendBlocking
    import kotlinx.coroutines.flow.Flow
    import kotlinx.coroutines.flow.callbackFlow
    import okio.ByteString
    import okio.ByteString.Companion.toByteString
    import org.lighthousegames.logging.logging

    class KtorZiplineHttpClient(
    private val httpClient: HttpClient
    ) : ZiplineHttpClient() {

    override suspend fun download(
    url: String,
    requestHeaders: List<Pair<String, String>>
    ): ByteString {
    val response: HttpResponse = httpClient.get(url) {
    headers {
    requestHeaders.forEach { (name, value) ->
    append(name, value)
    }
    }
    }

    if (!response.status.isSuccess()) {
    throw Exception("failed to fetch $url: ${response.status.value}")
    }

    return response.body<ByteArray>().toByteString()
    }

    override suspend fun openDevelopmentServerWebSocket(
    url: String,
    requestHeaders: List<Pair<String, String>>
    ): Flow<String> {
    return callbackFlow {
    val session = httpClient.webSocketSession(url) {
    requestHeaders.forEach { (name, value) ->
    headers.append(name, value)
    }
    }

    try {
    for (frame in session.incoming) {
    if (frame is Frame.Text) {
    trySendBlocking(frame.readText())
    }
    }
    } catch (e: Exception) {
    close(e)
    } finally {
    session.close()
    }
    }
    }
    }