Skip to content

Commit

Permalink
Remove Krossbow and use Ktor directly
Browse files Browse the repository at this point in the history
Resolves:
#190
  • Loading branch information
joffrey-bion committed Aug 20, 2022
1 parent 32825d9 commit 8fd9211
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 27 deletions.
6 changes: 3 additions & 3 deletions api/chrome-devtools-kotlin.api
Original file line number Diff line number Diff line change
Expand Up @@ -41508,8 +41508,8 @@ public final class org/hildan/chrome/devtools/extensions/CrossDomainExtensionsKt

public final class org/hildan/chrome/devtools/protocol/ChromeDPClient {
public fun <init> ()V
public fun <init> (Ljava/lang/String;ZLorg/hildan/krossbow/websocket/WebSocketClient;Lio/ktor/client/HttpClient;)V
public synthetic fun <init> (Ljava/lang/String;ZLorg/hildan/krossbow/websocket/WebSocketClient;Lio/ktor/client/HttpClient;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;ZLio/ktor/client/HttpClient;)V
public synthetic fun <init> (Ljava/lang/String;ZLio/ktor/client/HttpClient;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun activateTab (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun closeAllTargets (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun closeTab (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand All @@ -41522,7 +41522,7 @@ public final class org/hildan/chrome/devtools/protocol/ChromeDPClient {
}

public final class org/hildan/chrome/devtools/protocol/ChromeDPClientKt {
public static final fun connectToChrome (Lorg/hildan/krossbow/websocket/WebSocketClient;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun chromeWebSocket (Lio/ktor/client/HttpClient;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class org/hildan/chrome/devtools/protocol/ChromeDPTarget {
Expand Down
2 changes: 0 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ repositories {
}

dependencies {
api("org.hildan.krossbow:krossbow-websocket-core:4.1.0")
implementation("org.hildan.krossbow:krossbow-websocket-builtin:4.1.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.websocket.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
Expand All @@ -14,10 +15,6 @@ import kotlinx.serialization.json.Json
import org.hildan.chrome.devtools.targets.ChromeBrowserSession
import org.hildan.chrome.devtools.targets.ChromePageSession
import org.hildan.chrome.devtools.targets.attachToPage
import org.hildan.krossbow.websocket.WebSocketClient
import org.hildan.krossbow.websocket.builtin.builtIn

private val DEFAULT_WEBSOCKET_CLIENT by lazy { WebSocketClient.builtIn() }

private val DEFAULT_HTTP_CLIENT by lazy { createHttpClient(overrideHostHeader = false) }

Expand All @@ -27,6 +24,7 @@ private fun createHttpClient(overrideHostHeader: Boolean) = HttpClient {
install(ContentNegotiation) {
json(Json { ignoreUnknownKeys = true })
}
install(WebSockets)
if (overrideHostHeader) {
install(DefaultRequest) {
headers["Host"] = "localhost"
Expand All @@ -41,7 +39,7 @@ private fun createHttpClient(overrideHostHeader: Boolean) = HttpClient {
* the browser and its targets to make use of the full Chrome Devtools Protocol API.
*
* **Note:** if you already know the browser target's web socket URL, you don't need to create a `ChromeDPClient`.
* Instead, use a [WebSocketClient] and [WebSocketClient.connectToChrome][connectToChrome] instead.
* Instead, you can directly use [HttpClient.chromeWebSocket].
*
* ## Host override
*
Expand All @@ -64,11 +62,6 @@ class ChromeDPClient(
* Enables override of the `Host` header to `localhost` (see section about Host override in [ChromeDPClient] doc).
*/
private val overrideHostHeader: Boolean = false,
/**
* This parameter should usually be left to its default value.
* Only use this to work around an issue in the client's configuration/behaviour.
*/
private val webSocketClient: WebSocketClient = DEFAULT_WEBSOCKET_CLIENT,
/**
* This parameter should usually be left to its default value.
* Only use this to work around an issue in the client's configuration/behaviour.
Expand Down Expand Up @@ -124,7 +117,7 @@ class ChromeDPClient(
*/
suspend fun webSocket(): ChromeBrowserSession {
val browserDebuggerUrl = version().webSocketDebuggerUrl
return webSocketClient.connectToChrome(browserDebuggerUrl)
return httpClient.chromeWebSocket(browserDebuggerUrl)
}

private fun ChromeVersion.fixHost() = when {
Expand Down Expand Up @@ -188,7 +181,7 @@ data class ChromeDPTarget(
* [ChromeBrowserSession.attachToPage] or
* [ChromeBrowserSession.attachToNewPage][org.hildan.chrome.devtools.targets.attachToNewPage].
*/
suspend fun WebSocketClient.connectToChrome(webSocketDebuggerUrl: String): ChromeBrowserSession {
val connection = connect(webSocketDebuggerUrl).chromeDp()
suspend fun HttpClient.chromeWebSocket(webSocketDebuggerUrl: String): ChromeBrowserSession {
val connection = webSocketSession(webSocketDebuggerUrl).chromeDp()
return ChromeBrowserSession(connection.withSession(sessionId = null))
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
package org.hildan.chrome.devtools.protocol

import io.ktor.websocket.*
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.hildan.krossbow.websocket.WebSocketConnection
import org.hildan.krossbow.websocket.WebSocketFrame
import java.io.IOException

private val json = Json { ignoreUnknownKeys = true }

/**
* Wraps this [WebSocketConnection] to provide Chrome DevTools Protocol capabilities.
* Wraps this [WebSocketSession] to provide Chrome DevTools Protocol capabilities.
*
* The returned [ChromeDPConnection] can be used to send requests and listen to events.
*/
internal fun WebSocketConnection.chromeDp(): ChromeDPConnection = ChromeDPConnection(this)
internal fun WebSocketSession.chromeDp(): ChromeDPConnection = ChromeDPConnection(this)

/**
* A connection to Chrome, providing communication primitives for the Chrome DevTools protocol.
*
* It encodes/decodes ChromeDP frames, and handles sharing of incoming events.
*/
internal class ChromeDPConnection(
private val webSocket: WebSocketConnection
private val webSocket: WebSocketSession,
) {
private val coroutineScope = CoroutineScope(CoroutineName("ChromeDP-frame-decoder"))

private val frames = webSocket.incomingFrames
.filterIsInstance<WebSocketFrame.Text>()
.map { frame -> json.decodeFromString(InboundFrameSerializer, frame.text) }
private val frames = webSocket.incoming.receiveAsFlow()
.filterIsInstance<Frame.Text>()
.map { frame -> json.decodeFromString(InboundFrameSerializer, frame.readText()) }
.shareIn(
scope = coroutineScope,
started = SharingStarted.Eagerly,
Expand All @@ -39,8 +39,12 @@ internal class ChromeDPConnection(
*
* Throws [RequestFailed] in case of error.
*/
@OptIn(ExperimentalCoroutinesApi::class)
suspend fun request(request: RequestFrame): ResponseFrame {
val resultFrame = frames.onSubscription { webSocket.sendText(json.encodeToString(request)) }
if (webSocket.outgoing.isClosedForSend) {
throw IOException("Cannot perform Chrome DevTools request ${request.method}, the web socket is closed.")
}
val resultFrame = frames.onSubscription { webSocket.send(json.encodeToString(request)) }
.filterIsInstance<ResultFrame>()
.filter { it.matchesRequest(request) }
.first() // a shared flow never completes anyway, so this will never throw (but can hang forever)
Expand Down

0 comments on commit 8fd9211

Please sign in to comment.