Refactor KMP networking backends
This commit is contained in:
1 parent
d0aaa2c256
commit
cd7e001f41
22 files changed
+706
-851
No files matched your search
@@ -1,58 +1,5 @@
|
||||
package net.sergeych.lyngio.http
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.engine.js.Js
|
||||
import io.ktor.client.plugins.timeout
|
||||
import io.ktor.client.request.HttpRequestBuilder
|
||||
import io.ktor.client.request.request
|
||||
import io.ktor.client.request.setBody
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.headers
|
||||
import io.ktor.http.takeFrom
|
||||
|
||||
actual fun getSystemHttpEngine(): LyngHttpEngine = JsKtorLyngHttpEngine
|
||||
|
||||
private object JsKtorLyngHttpEngine : LyngHttpEngine {
|
||||
private val clientResult by lazy {
|
||||
runCatching {
|
||||
HttpClient(Js) {
|
||||
expectSuccess = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val isSupported: Boolean
|
||||
get() = clientResult.isSuccess
|
||||
|
||||
override suspend fun request(request: LyngHttpRequest): LyngHttpResponse {
|
||||
val httpClient = clientResult.getOrElse {
|
||||
throw UnsupportedOperationException(it.message ?: "HTTP client is not supported")
|
||||
}
|
||||
|
||||
val response = httpClient.request {
|
||||
applyRequest(request)
|
||||
}
|
||||
return LyngHttpResponse(
|
||||
status = response.status.value,
|
||||
statusText = response.status.description,
|
||||
headers = response.headers.entries().associate { it.key to it.value.toList() },
|
||||
bodyBytes = response.body<ByteArray>(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun HttpRequestBuilder.applyRequest(request: LyngHttpRequest) {
|
||||
method = HttpMethod.parse(request.method.uppercase())
|
||||
url.takeFrom(request.url)
|
||||
headers {
|
||||
request.headers.forEach { (name, value) -> append(name, value) }
|
||||
}
|
||||
request.timeoutMillis?.let { timeout { requestTimeoutMillis = it } }
|
||||
when {
|
||||
request.bodyBytes != null && request.bodyText != null ->
|
||||
throw IllegalArgumentException("Only one of bodyText or bodyBytes may be set")
|
||||
request.bodyBytes != null -> setBody(request.bodyBytes)
|
||||
request.bodyText != null -> setBody(request.bodyText)
|
||||
}
|
||||
}
|
||||
}
|
||||
actual fun getSystemHttpEngine(): LyngHttpEngine = createKtorHttpEngine(Js)
|
||||
@@ -1,91 +1,5 @@
|
||||
package net.sergeych.lyngio.ws
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.js.Js
|
||||
import io.ktor.client.plugins.websocket.WebSockets
|
||||
import io.ktor.client.plugins.websocket.webSocketSession
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.url
|
||||
import io.ktor.websocket.CloseReason
|
||||
import io.ktor.websocket.DefaultWebSocketSession
|
||||
import io.ktor.websocket.Frame
|
||||
import io.ktor.websocket.close
|
||||
import io.ktor.websocket.readText
|
||||
import io.ktor.websocket.send
|
||||
import kotlinx.coroutines.channels.ClosedReceiveChannelException
|
||||
|
||||
actual fun getSystemWsEngine(): LyngWsEngine = JsKtorWsEngine
|
||||
|
||||
private object JsKtorWsEngine : LyngWsEngine {
|
||||
private val clientResult by lazy {
|
||||
runCatching {
|
||||
HttpClient(Js) {
|
||||
install(WebSockets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val isSupported: Boolean
|
||||
get() = clientResult.isSuccess
|
||||
|
||||
override suspend fun connect(url: String, headers: Map<String, String>): LyngWsSession {
|
||||
val client = clientResult.getOrElse {
|
||||
throw UnsupportedOperationException(it.message ?: "WebSocket client is not supported")
|
||||
}
|
||||
val session = client.webSocketSession {
|
||||
url(url)
|
||||
headers.forEach { (name, value) -> header(name, value) }
|
||||
}
|
||||
return JsLyngWsSession(url, session)
|
||||
}
|
||||
}
|
||||
|
||||
private class JsLyngWsSession(
|
||||
private val targetUrl: String,
|
||||
private val session: DefaultWebSocketSession,
|
||||
) : LyngWsSession {
|
||||
private var closed = false
|
||||
|
||||
override fun isOpen(): Boolean = !closed
|
||||
|
||||
override fun url(): String = targetUrl
|
||||
|
||||
override suspend fun sendText(text: String) {
|
||||
ensureOpen()
|
||||
session.send(text)
|
||||
}
|
||||
|
||||
override suspend fun sendBytes(data: ByteArray) {
|
||||
ensureOpen()
|
||||
session.send(data)
|
||||
}
|
||||
|
||||
override suspend fun receive(): LyngWsMessage? {
|
||||
if (closed) return null
|
||||
val frame = try {
|
||||
session.incoming.receive()
|
||||
} catch (_: ClosedReceiveChannelException) {
|
||||
closed = true
|
||||
return null
|
||||
}
|
||||
return when (frame) {
|
||||
is Frame.Text -> LyngWsMessage(isText = true, text = frame.readText())
|
||||
is Frame.Binary -> LyngWsMessage(isText = false, data = frame.data.copyOf())
|
||||
is Frame.Close -> {
|
||||
closed = true
|
||||
null
|
||||
}
|
||||
else -> receive()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun close(code: Int, reason: String) {
|
||||
if (closed) return
|
||||
closed = true
|
||||
session.close(CloseReason(code.toShort(), reason))
|
||||
}
|
||||
|
||||
private fun ensureOpen() {
|
||||
if (closed) throw IllegalStateException("websocket session is closed")
|
||||
}
|
||||
}
|
||||
actual fun getSystemWsEngine(): LyngWsEngine = createKtorWsEngine(Js)
|
||||
Reference in new issue
Block a user