├── CONTRIBUTING.md
├── src
├── main
│ ├── kotlin
│ │ └── pl
│ │ │ └── wendigo
│ │ │ └── chrome
│ │ │ ├── api
│ │ │ ├── inspector
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── tethering
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── deviceorientation
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── io
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── schema
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── performance
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── cast
│ │ │ │ └── Types.kt
│ │ │ ├── headlessexperimental
│ │ │ │ └── Types.kt
│ │ │ ├── domstorage
│ │ │ │ └── Types.kt
│ │ │ ├── console
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── database
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── log
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── applicationcache
│ │ │ │ └── Types.kt
│ │ │ ├── storage
│ │ │ │ └── Types.kt
│ │ │ ├── target
│ │ │ │ └── Types.kt
│ │ │ ├── memory
│ │ │ │ └── Types.kt
│ │ │ ├── heapprofiler
│ │ │ │ └── Types.kt
│ │ │ ├── domdebugger
│ │ │ │ └── Types.kt
│ │ │ ├── backgroundservice
│ │ │ │ └── Types.kt
│ │ │ ├── media
│ │ │ │ ├── Types.kt
│ │ │ │ └── Domain.kt
│ │ │ ├── tracing
│ │ │ │ └── Types.kt
│ │ │ ├── systeminfo
│ │ │ │ └── Domain.kt
│ │ │ ├── cachestorage
│ │ │ │ └── Types.kt
│ │ │ ├── performancetimeline
│ │ │ │ ├── Domain.kt
│ │ │ │ └── Types.kt
│ │ │ ├── input
│ │ │ │ └── Types.kt
│ │ │ ├── fetch
│ │ │ │ └── Types.kt
│ │ │ ├── animation
│ │ │ │ └── Types.kt
│ │ │ ├── serviceworker
│ │ │ │ └── Types.kt
│ │ │ ├── emulation
│ │ │ │ └── Types.kt
│ │ │ ├── webauthn
│ │ │ │ └── Types.kt
│ │ │ ├── indexeddb
│ │ │ │ └── Types.kt
│ │ │ ├── layertree
│ │ │ │ └── Types.kt
│ │ │ └── audits
│ │ │ │ └── Domain.kt
│ │ │ ├── protocol
│ │ │ ├── Experimental.kt
│ │ │ ├── websocket
│ │ │ │ ├── RequestError.kt
│ │ │ │ ├── RequestFrame.kt
│ │ │ │ ├── WebSocketFrame.kt
│ │ │ │ ├── FrameMapper.kt
│ │ │ │ └── WebSocketFramesStream.kt
│ │ │ ├── Exceptions.kt
│ │ │ ├── Domains.kt
│ │ │ ├── EventMapper.kt
│ │ │ ├── Event.kt
│ │ │ ├── Domain.kt
│ │ │ └── ProtocolConnection.kt
│ │ │ ├── BrowserInfoDiscoveryFailedException.kt
│ │ │ ├── BuildInfo.kt
│ │ │ ├── targets
│ │ │ ├── SessionTarget.kt
│ │ │ ├── TargetInfoExtensions.kt
│ │ │ ├── Target.kt
│ │ │ └── Manager.kt
│ │ │ ├── RxExtensions.kt
│ │ │ ├── HeadlessChromeContainer.kt
│ │ │ └── ContainerizedBrowser.kt
│ └── resources
│ │ ├── version.json
│ │ └── logback.xml
├── test
│ ├── resources
│ │ └── logback.xml
│ └── groovy
│ │ └── pl
│ │ └── wendigo
│ │ └── chrome
│ │ └── ChromeProtocolSpecification.groovy
└── samples
│ └── kotlin
│ └── pl
│ └── wendigo
│ └── chrome
│ └── samples
│ ├── CreateBrowser.kt
│ ├── CreateNewTarget.kt
│ └── Containerized.kt
├── deploy
├── private.gpg.enc
└── deploy.sh
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .editorconfig
├── .gitignore
├── generator_templates
├── markdown.hbs
├── event_serializers.hbs
├── input_data_class.hbs
├── output_data_class.hbs
├── types.hbs
├── protocol_domains.hbs
└── protocol_domain.hbs
├── .github
└── workflows
│ ├── update-protocol.yml.disabled
│ ├── tests-with-gradle.yml
│ ├── publish-dokka-docs-to-gh-pages.yml
│ ├── release-to-ossrh.yml
│ └── codeql-analysis.yml
├── update.sh
├── package.md
├── gradlew.bat
├── CODE_OF_CONDUCT.md
├── README.md
└── gradlew
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Principles
2 |
3 | 1. Contribute good code. Thanks!
4 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/inspector/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.inspector
2 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/tethering/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.tethering
2 |
--------------------------------------------------------------------------------
/deploy/private.gpg.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendigo/chrome-reactive-kotlin/HEAD/deploy/private.gpg.enc
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/deviceorientation/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.deviceorientation
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendigo/chrome-reactive-kotlin/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{kt,kts}]
2 | indent_size=4
3 | insert_final_newline=true
4 | max_line_length=off
5 | disabled_rules=no-trailing-spaces,filename
6 |
--------------------------------------------------------------------------------
/src/main/resources/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "@version@",
3 | "revision": "@revision@",
4 | "branch": "@branch@",
5 | "group": "@group@",
6 | "name": "@name@"
7 | }
--------------------------------------------------------------------------------
/deploy/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -xeuo pipefail
3 |
4 | ./gradlew assemble
5 | ./gradlew publishToSonatype -i -P githubToken=$GITHUB_ACCESS_TOKEN
6 | ./gradlew closeAndReleaseRepository -i -P githubToken=$GITHUB_ACCESS_TOKEN
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .gradle
3 | build
4 | src/main/kotlin/pl/wendigo/chrome/Test.kt
5 | logs/
6 | v8_protocol.json
7 | browser_protocol.json
8 | out
9 | *.iml
10 | *.ipr
11 | *.iws
12 | *.pyc
13 | *.py
14 | *.pdl
15 | gradle.properties
16 | *.sh
17 | *.gpg
18 |
--------------------------------------------------------------------------------
/generator_templates/markdown.hbs:
--------------------------------------------------------------------------------
1 | # Module Chrome Reactive Kotlin
2 |
3 | {{#each Domains}}
4 | # Package pl.wendigo.chrome.api.{{LowerName}}
5 |
6 | Contains DevTools Protocol [{{Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Name}}) domain implementation accessible via [{{Name}}Domain] class.
7 |
8 | {{/each}}
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/Experimental.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol
2 |
3 | import kotlin.Experimental
4 |
5 | /**
6 | * This annotation is used on DevTools Protocol APIs and types that are marked as experimental.
7 | */
8 | @Experimental(level = Experimental.Level.WARNING)
9 | annotation class Experimental
10 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/BrowserInfoDiscoveryFailedException.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome
2 |
3 | import java.lang.RuntimeException
4 |
5 | /**
6 | * BrowserInfoDiscoveryFailedException is thrown when there's no possibility to query browser for debugger WebSocket endpoint.
7 | */
8 | class BrowserInfoDiscoveryFailedException(reason: String) : RuntimeException(reason)
9 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/io/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.io
2 |
3 | /**
4 | * This is either obtained from another method or specifed as `blob:<uuid>` where
5 | `<uuid>` is an UUID of a Blob.
6 | *
7 | * @link [IO#StreamHandle](https://chromedevtools.github.io/devtools-protocol/tot/IO#type-StreamHandle) type documentation.
8 | */
9 |
10 | typealias StreamHandle = String
11 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/BuildInfo.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class BuildInfo(
7 | val version: String,
8 | val revision: String,
9 | val branch: String,
10 | val group: String,
11 | val name: String
12 | ) {
13 | override fun toString(): String {
14 | return "$group:$name:$version built from $branch, rev $revision"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.github/workflows/update-protocol.yml.disabled:
--------------------------------------------------------------------------------
1 | name: Update protocol to ToT
2 |
3 | on:
4 | schedule:
5 | - cron: '0 */6 * * *'
6 |
7 | jobs:
8 | update:
9 | name: "Update protocol via update.sh"
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v1
13 | - name: Update protocol
14 | run: ./update.sh
15 | env:
16 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
17 | GITHUB_REPOSITORY: ${{ github.repository }}
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/targets/SessionTarget.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.targets
2 |
3 | import pl.wendigo.chrome.api.browser.BrowserContextID
4 | import pl.wendigo.chrome.api.target.SessionID
5 | import pl.wendigo.chrome.api.target.TargetID
6 |
7 | /**
8 | * SessionTarget represents multiplexed session we are currently connected to.
9 | */
10 | data class SessionTarget(
11 | val sessionId: SessionID,
12 | val targetId: TargetID,
13 | val browserContextID: BrowserContextID? = null
14 | )
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/websocket/RequestError.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol.websocket
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Represents protocol error.
7 | */
8 | @Serializable
9 | data class RequestError(
10 | /**
11 | * Error code.
12 | */
13 | val code: Long,
14 |
15 | /**
16 | * Error message.
17 | */
18 | val message: String,
19 |
20 | /**
21 | * Associated error data.
22 | */
23 | val data: String? = null
24 | )
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/schema/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.schema
2 |
3 | /**
4 | * Description of the protocol domain.
5 | *
6 | * @link [Schema#Domain](https://chromedevtools.github.io/devtools-protocol/tot/Schema#type-Domain) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class Domain(
11 | /**
12 | * Domain name.
13 | */
14 | val name: String,
15 |
16 | /**
17 | * Domain version.
18 | */
19 | val version: String
20 | )
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/performance/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.performance
2 |
3 | /**
4 | * Run-time execution metric.
5 | *
6 | * @link [Performance#Metric](https://chromedevtools.github.io/devtools-protocol/tot/Performance#type-Metric) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class Metric(
11 | /**
12 | * Metric name.
13 | */
14 | val name: String,
15 |
16 | /**
17 | * Metric value.
18 | */
19 | val value: Double
20 | )
21 |
--------------------------------------------------------------------------------
/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{HH:mm:ss.SSS} %-5level %-46logger: %msg%n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{HH:mm:ss.SSS} %-5level %-46logger: %msg%n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/targets/TargetInfoExtensions.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.targets
2 |
3 | import pl.wendigo.chrome.api.target.SessionID
4 | import pl.wendigo.chrome.api.target.TargetInfo
5 |
6 | /**
7 | * Returns true if [TargetInfo] represents page.
8 | */
9 | fun TargetInfo.isPage() = this.type == "page"
10 |
11 | /**
12 | * Converts [TargetInfo] to [SessionTarget] for given sessionID
13 | */
14 | fun TargetInfo.toTarget(sessionId: SessionID): SessionTarget = SessionTarget(
15 | sessionId = sessionId,
16 | targetId = this.targetId,
17 | browserContextID = this.browserContextId
18 | )
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/cast/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.cast
2 |
3 | /**
4 | *
5 | *
6 | * @link [Cast#Sink](https://chromedevtools.github.io/devtools-protocol/tot/Cast#type-Sink) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class Sink(
11 | /**
12 | *
13 | */
14 | val name: String,
15 |
16 | /**
17 | *
18 | */
19 | val id: String,
20 |
21 | /**
22 | * Text describing the current session. Present only if there is an active
23 | session on the sink.
24 | */
25 | val session: String? = null
26 | )
27 |
--------------------------------------------------------------------------------
/src/samples/kotlin/pl/wendigo/chrome/samples/CreateBrowser.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.samples
2 |
3 | import pl.wendigo.chrome.Browser
4 |
5 | object CreateBrowser {
6 | @JvmStatic
7 | fun main(args: Array) {
8 | val browser = Browser.builder()
9 | .withAddress("127.0.0.1:9222")
10 | .withBlankPage("about:blank")
11 | .withViewportWidth(1280)
12 | .withViewportHeight(1024)
13 | .withEventsBufferSize(128)
14 | .multiplexConnections(true)
15 | .incognito(true)
16 | .build()
17 |
18 | println(browser.browserInfo())
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.github/workflows/tests-with-gradle.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | pull_request:
9 | branches:
10 | - master
11 |
12 | jobs:
13 | test:
14 | name: "Run all tests"
15 | runs-on: ubuntu-latest
16 | env:
17 | GRADLE_OPTS: "-Xmx8198m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError"
18 | GRADLE_FLAGS: "--no-daemon -i"
19 | steps:
20 | - name: Checkout code
21 | uses: actions/checkout@v2
22 |
23 | - name: Set up Java 11
24 | uses: actions/setup-java@v1
25 | with:
26 | java-version: 11
27 |
28 | - name: Run tests
29 | run: ./gradlew clean test ${GRADLE_FLAGS}
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/headlessexperimental/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.headlessexperimental
2 |
3 | /**
4 | * Encoding options for a screenshot.
5 | *
6 | * @link [HeadlessExperimental#ScreenshotParams](https://chromedevtools.github.io/devtools-protocol/tot/HeadlessExperimental#type-ScreenshotParams) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class ScreenshotParams(
11 | /**
12 | * Image compression format (defaults to png).
13 | */
14 | val format: String? = null,
15 |
16 | /**
17 | * Compression quality from range [0..100] (jpeg only).
18 | */
19 | val quality: Int? = null
20 | )
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/RxExtensions.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome
2 |
3 | import io.reactivex.rxjava3.core.Flowable
4 | import io.reactivex.rxjava3.core.Single
5 |
6 | typealias SingleBlock = () -> Single
7 | typealias FlowableBlock = () -> Flowable
8 |
9 | fun sync(block: SingleBlock): T where T : Any {
10 | return block.invoke().blockingGet()
11 | }
12 |
13 | fun sync(single: Single): T where T : Any {
14 | return single.blockingGet()
15 | }
16 |
17 | fun awaitMany(block: FlowableBlock): List {
18 | return block.invoke().toList().blockingGet()
19 | }
20 |
21 | fun on(flowable: Flowable, listener: (T) -> Unit) {
22 | flowable.subscribe(listener)
23 | }
24 |
--------------------------------------------------------------------------------
/generator_templates/event_serializers.hbs:
--------------------------------------------------------------------------------
1 | package {{Package}}.api
2 |
3 | import kotlinx.serialization.KSerializer
4 | import pl.wendigo.chrome.protocol.Event
5 | import pl.wendigo.chrome.protocol.websocket.EventResponseFrame
6 |
7 | /**
8 | * EventSerializers is responsible for mapping [EventResponseFrame] to [KSerializer] that can decode this frame to [Event].
9 | */
10 | object EventSerializers {
11 | /**
12 | * Returns [Event] serializer that can decode given [EventResponseFrame] frame.
13 | */
14 | fun getByEventName(frame: EventResponseFrame): KSerializer = when(frame.eventName) {
15 | {{#each Events}}
16 | "{{EventName}}" -> {{Class}}.serializer()
17 | {{/each}}
18 | else -> throw RuntimeException("Unrecognized event frame $frame")
19 | }
20 | }
--------------------------------------------------------------------------------
/generator_templates/input_data_class.hbs:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents request frame that can be used with [{{Domain}}#{{Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain}}#method-{{Name}}) operation call.
3 | *
4 | *{{{trim Description}}}
5 | * @link [{{Domain}}#{{Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain}}#method-{{Name}}) method documentation.
6 | * @see [{{Domain}}Domain.{{Name}}]
7 | */
8 | @kotlinx.serialization.Serializable
9 | data class {{SimpleName}}Request (
10 | {{#each Parameters}}
11 | /**
12 | *{{{trim Description}}}
13 | */
14 | {{#if Experimental}}@{{Package}}.protocol.Experimental {{/if}}{{#if Deprecated}}@Deprecated(message="") {{/if}}{{{value Name}}}: {{{GetFormattedType}}}{{#if Optional}}? = null{{/if}}{{#unless @last}},{{/unless}}
15 |
16 | {{/each}}
17 | )
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/domstorage/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.domstorage
2 |
3 | /**
4 | * DOM Storage identifier.
5 | *
6 | * @link [DOMStorage#StorageId](https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#type-StorageId) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class StorageId(
11 | /**
12 | * Security origin for the storage.
13 | */
14 | val securityOrigin: String,
15 |
16 | /**
17 | * Whether the storage is local storage (not session storage).
18 | */
19 | val isLocalStorage: Boolean
20 | )
21 |
22 | /**
23 | * DOM Storage item.
24 | *
25 | * @link [DOMStorage#Item](https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#type-Item) type documentation.
26 | */
27 |
28 | typealias Item = List
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/websocket/RequestFrame.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol.websocket
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonElement
6 |
7 | /**
8 | * Represents request frame.
9 | */
10 | @Serializable
11 | data class RequestFrame(
12 | /**
13 | * Request id, must be unique.
14 | */
15 | val id: Long,
16 |
17 | /**
18 | * Session ID for Target's flatten mode requests (see [http://crbug.com/991325](http://crbug.com/991325)).
19 | */
20 | @SerialName("sessionId")
21 | val sessionId: String? = null,
22 |
23 | /**
24 | * Protocol method (domain.method_name i.e. Page.navigateTo)
25 | */
26 | val method: String,
27 |
28 | /**
29 | * Request params (if any)
30 | */
31 | val params: JsonElement?
32 | )
33 |
--------------------------------------------------------------------------------
/src/samples/kotlin/pl/wendigo/chrome/samples/CreateNewTarget.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.samples
2 |
3 | import pl.wendigo.chrome.Browser
4 | import pl.wendigo.chrome.sync
5 |
6 | object CreateNewTarget {
7 | @JvmStatic
8 | fun main(args: Array) {
9 | val browser = Browser.builder()
10 | .withAddress("127.0.0.1:9222")
11 | .withBlankPage("about:blank")
12 | .withViewportWidth(1280)
13 | .withViewportHeight(1024)
14 | .withEventsBufferSize(128)
15 | .multiplexConnections(true)
16 | .incognito(true)
17 | .build()
18 |
19 | // create new Target that will start loading google.com
20 | val target = browser.target(url = "https://google.com")
21 |
22 | // enable Page domain events
23 | sync(target.Page.enable())
24 |
25 | // wait for the page to load
26 | sync(target.Page.loadEventFired().firstOrError())
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/console/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.console
2 |
3 | /**
4 | * Console message.
5 | *
6 | * @link [Console#ConsoleMessage](https://chromedevtools.github.io/devtools-protocol/tot/Console#type-ConsoleMessage) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class ConsoleMessage(
11 | /**
12 | * Message source.
13 | */
14 | val source: String,
15 |
16 | /**
17 | * Message severity.
18 | */
19 | val level: String,
20 |
21 | /**
22 | * Message text.
23 | */
24 | val text: String,
25 |
26 | /**
27 | * URL of the message origin.
28 | */
29 | val url: String? = null,
30 |
31 | /**
32 | * Line number in the resource that generated this message (1-based).
33 | */
34 | val line: Int? = null,
35 |
36 | /**
37 | * Column number in the resource that generated this message (1-based).
38 | */
39 | val column: Int? = null
40 | )
41 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/Exceptions.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol
2 |
3 | import pl.wendigo.chrome.protocol.websocket.RequestFrame
4 |
5 | /**
6 | * Frame deserialization failed on object mapper.
7 | */
8 | class DeserializationFailed constructor(override val message: String, throwable: Throwable?) : Exception(message, throwable)
9 |
10 | /**
11 | * Frame serialization failed on object mapper.
12 | */
13 | class SerializationFailed constructor(override val message: String, throwable: Throwable?) : Exception(message, throwable)
14 |
15 | /**
16 | * Protocol request has failed.
17 | */
18 | class RequestFailed constructor(override val message: String, throwable: Throwable?) : Exception(message, throwable) {
19 | constructor(request: RequestFrame, message: String) : this("request = $request, error = $message", null)
20 | }
21 |
22 | /**
23 | * Inspector command has failed.
24 | */
25 | class InspectorCommandFailed constructor(override val message: String, throwable: Throwable?) : Exception(message, throwable) {
26 | constructor(message: String) : this(message, null)
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/HeadlessChromeContainer.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome
2 |
3 | import org.testcontainers.containers.GenericContainer
4 | import org.testcontainers.utility.DockerImageName
5 |
6 | internal class HeadlessChromeContainer(dockerImageName: DockerImageName) : GenericContainer(dockerImageName) {
7 | init {
8 | this
9 | .withCommand(
10 | "chromium-browser",
11 | "--headless",
12 | "--disable-gpu",
13 | "--disable-software-rasterizer",
14 | "--disable-dev-shm-usage",
15 | "--no-sandbox",
16 | "--disable-setuid-sandbox",
17 | "--remote-debugging-port=9222",
18 | "--remote-debugging-address=0.0.0.0",
19 | "about:blank"
20 | )
21 | .withPrivilegedMode(true)
22 | .withReuse(true)
23 |
24 | this.addExposedPort(9222)
25 | }
26 |
27 | fun getBrowserEndpoint(): String {
28 | return this.containerIpAddress + ":" + this.getMappedPort(9222)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/generator_templates/output_data_class.hbs:
--------------------------------------------------------------------------------
1 | /**
2 | {{#if IsOutput}}
3 | * Represents response frame that is returned from [{{Domain}}#{{Type.Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain}}#method-{{Type.Name}}) operation call.
4 | {{/if}}
5 | *{{{trim Type.Description}}}
6 | *
7 | {{#if IsEvent}}
8 | * @link [{{Domain}}#{{Type.Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain}}#event-{{Type.Name}}) event documentation.
9 | {{/if}}
10 | {{#if IsOutput}}
11 | * @link [{{Domain}}#{{Type.Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain}}#method-{{Type.Name}}) method documentation.
12 | * @see [{{Domain}}Domain.{{Type.Name}}]
13 | {{/if}}
14 | */
15 | @kotlinx.serialization.Serializable
16 | data class {{Type.ClassName}}(
17 | {{#each Type.Returns}}
18 | /**
19 | *{{{trim Description}}}
20 | */
21 | {{#if Type.Experimental}}@Experimental {{/if}}{{#if Type.Deprecated}}@Deprecated {{/if}}{{{value Name}}}: {{{GetFormattedType}}}{{#if Optional}}? = null{{/if}}{{#unless @last}},{{/unless}}
22 |
23 | {{/each}}
24 | ){{#if Type.ImplementingInterfaces}}: {{{ Type.ImplementingInterfaces }}} {{/if}}
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/Domains.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol
2 |
3 | import io.reactivex.rxjava3.core.Flowable
4 | import pl.wendigo.chrome.api.target.SessionID
5 | import java.io.Closeable
6 |
7 | open class Domains internal constructor(
8 | private val protocolVersion: String,
9 | /**
10 | * Connection that is used to execute [Domain] methods and receive generated events.
11 | */
12 | protected val connection: ProtocolConnection
13 | ) : Closeable, AutoCloseable {
14 | /**
15 | * Returns [Flowable] capturing all events.
16 | */
17 | fun events(): Flowable {
18 | return connection.events()
19 | }
20 |
21 | /**
22 | * Closes underlying debugger WebSocket connection.
23 | */
24 | override fun close() {
25 | return connection.close()
26 | }
27 |
28 | /**
29 | * Returns protocol version.
30 | */
31 | fun protocolVersion(): String {
32 | return protocolVersion
33 | }
34 |
35 | /**
36 | * Clones multiplexed connection with new session ID.
37 | */
38 | internal fun cloneConnection(sessionID: SessionID) = connection.cloneForSessionId(sessionID)
39 | }
40 |
--------------------------------------------------------------------------------
/generator_templates/types.hbs:
--------------------------------------------------------------------------------
1 | package {{Package}}.api.{{Domain.LowerName}}
2 |
3 | {{#each Domain.Types}}
4 | /**
5 | *{{trim Description}}
6 | *
7 | * @link [{{Domain.Name}}#{{Id}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain.Name}}#type-{{Id}}) type documentation.
8 | */
9 | {{#if IsEnum}}@kotlinx.serialization.Serializable
10 | enum class {{Id}} {
11 | {{#each Enum}}
12 | @kotlinx.serialization.SerialName("{{.}}") {{EnumName .}}{{#unless @last}},{{else}};{{/unless}}
13 | {{/each}}
14 | }{{else}}
15 | {{#equal Type "string"}}typealias {{Id}} = String{{/equal}}{{#equal Type "number"}}typealias {{Id}} = Double{{/equal}}{{#equal Type "integer"}}typealias {{Id}} = Int{{/equal}}{{#equal Type "array"}}typealias {{Id}} = {{{GetFormattedType}}}{{/equal}}{{#equal Type "object"}}{{#if HasProperties}}@kotlinx.serialization.Serializable
16 | data class {{Id}}({{#each Properties}}
17 | /**
18 | *{{{trim Description}}}
19 | */
20 | {{#if Experimental}}@{{Package}}.protocol.Experimental {{/if}}{{#if Deprecated}}@Deprecated(message="") {{/if}}{{{value Name}}}: {{{GetFormattedType}}}{{#if Optional}}? = null{{/if}}{{#unless @last}},{{/unless}}
21 | {{/each}}
22 | ){{else}}typealias {{Id}} = Map{{/if}}{{/equal}}{{/if}}
23 |
24 | {{/each}}
25 |
--------------------------------------------------------------------------------
/.github/workflows/publish-dokka-docs-to-gh-pages.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy Docs
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | build-and-deploy:
8 | name: "Build and deploy docs to GH pages"
9 | runs-on: ubuntu-latest
10 | env:
11 | GRADLE_OPTS: "-Xmx8198m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError"
12 | GRADLE_FLAGS: "--no-daemon -i"
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v1
16 | - name: Cache Gradle dependencies
17 | uses: actions/cache@v2
18 | with:
19 | path: |
20 | ~/.gradle/caches
21 | ~/.gradle/wrapper
22 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
23 | restore-keys: |
24 | ${{ runner.os }}-gradle-
25 | - name: Build docs
26 | run: ./gradlew clean dokkaHtml ${GRADLE_FLAGS}
27 | - name: Touch .nojekyll
28 | run: |
29 | echo 1 > build/dokka/html/.nojekyll && echo "theme: jekyll-theme-cayman" > build/dokka/html/_config.yml
30 | - name: Build and Deploy
31 | uses: JamesIves/github-pages-deploy-action@4.1.0
32 | with:
33 | token: ${{ secrets.ACCESS_TOKEN }}
34 | branch: gh-pages
35 | folder: build/dokka/html
36 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/database/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.database
2 |
3 | /**
4 | * Unique identifier of Database object.
5 | *
6 | * @link [Database#DatabaseId](https://chromedevtools.github.io/devtools-protocol/tot/Database#type-DatabaseId) type documentation.
7 | */
8 |
9 | typealias DatabaseId = String
10 |
11 | /**
12 | * Database object.
13 | *
14 | * @link [Database#Database](https://chromedevtools.github.io/devtools-protocol/tot/Database#type-Database) type documentation.
15 | */
16 |
17 | @kotlinx.serialization.Serializable
18 | data class Database(
19 | /**
20 | * Database ID.
21 | */
22 | val id: DatabaseId,
23 |
24 | /**
25 | * Database domain.
26 | */
27 | val domain: String,
28 |
29 | /**
30 | * Database name.
31 | */
32 | val name: String,
33 |
34 | /**
35 | * Database version.
36 | */
37 | val version: String
38 | )
39 |
40 | /**
41 | * Database error.
42 | *
43 | * @link [Database#Error](https://chromedevtools.github.io/devtools-protocol/tot/Database#type-Error) type documentation.
44 | */
45 |
46 | @kotlinx.serialization.Serializable
47 | data class Error(
48 | /**
49 | * Error message.
50 | */
51 | val message: String,
52 |
53 | /**
54 | * Error code.
55 | */
56 | val code: Int
57 | )
58 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/schema/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.schema
2 |
3 | /**
4 | * This domain is deprecated.
5 | *
6 | * @link Protocol [Schema](https://chromedevtools.github.io/devtools-protocol/tot/Schema) domain documentation.
7 | */
8 | @Deprecated(level = DeprecationLevel.WARNING, message = "This domain is deprecated.")
9 | class SchemaDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
10 | pl.wendigo.chrome.protocol.Domain("Schema", """This domain is deprecated.""", connection) {
11 | /**
12 | * Returns supported domains.
13 | *
14 | * @link Protocol [Schema#getDomains](https://chromedevtools.github.io/devtools-protocol/tot/Schema#method-getDomains) method documentation.
15 | */
16 |
17 | fun getDomains(): io.reactivex.rxjava3.core.Single = connection.request("Schema.getDomains", null, GetDomainsResponse.serializer())
18 | }
19 |
20 | /**
21 | * Represents response frame that is returned from [Schema#getDomains](https://chromedevtools.github.io/devtools-protocol/tot/Schema#method-getDomains) operation call.
22 | * Returns supported domains.
23 | *
24 |
25 | * @link [Schema#getDomains](https://chromedevtools.github.io/devtools-protocol/tot/Schema#method-getDomains) method documentation.
26 | * @see [SchemaDomain.getDomains]
27 | */
28 | @kotlinx.serialization.Serializable
29 | data class GetDomainsResponse(
30 | /**
31 | * List of supported domains.
32 | */
33 | val domains: List
34 |
35 | )
36 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/EventMapper.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol
2 |
3 | import kotlinx.serialization.KSerializer
4 | import kotlinx.serialization.json.Json
5 | import pl.wendigo.chrome.api.EventSerializers
6 | import pl.wendigo.chrome.protocol.websocket.EventResponseFrame
7 |
8 | /**
9 | * EventMapper is responsible for mapping events carried by [EventResponseFrame] to concrete events representations.
10 | */
11 | class EventMapper {
12 | fun deserialize(eventFrame: EventResponseFrame, eventSerializer: KSerializer): T where T : Event {
13 | try {
14 | if (eventSerializer == RawEvent.serializer()) {
15 | @Suppress("UNCHECKED_CAST")
16 | return Event.fromFrame(eventFrame) as T
17 | }
18 |
19 | return decoder.decodeFromJsonElement(eventSerializer, eventFrame.params)
20 | } catch (e: Throwable) {
21 | throw DeserializationFailed("Could not deserialize event $eventFrame with $eventSerializer", e)
22 | }
23 | }
24 |
25 | /**
26 | * Deserializes [EventResponseFrame] into concrete event type representation using
27 | * serializer returned by [EventSerializers.getByEventName].
28 | */
29 | fun deserialize(eventFrame: EventResponseFrame): Event {
30 | return deserialize(eventFrame, EventSerializers.getByEventName(eventFrame))
31 | }
32 |
33 | companion object {
34 | private val decoder = Json {
35 | ignoreUnknownKeys = true;
36 | isLenient = true
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/Event.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol
2 |
3 | import kotlinx.serialization.Serializable
4 | import pl.wendigo.chrome.api.target.SessionID
5 | import pl.wendigo.chrome.protocol.websocket.EventResponseFrame
6 |
7 | /**
8 | * Represents event that can be generated by Chrome's debugger.
9 | */
10 | interface Event {
11 | /**
12 | * Returns event name as described in protocol.
13 | */
14 | fun eventName(): String
15 |
16 | /**
17 | * Returns domain name for which event was generated.
18 | */
19 | fun domain(): String
20 |
21 | companion object {
22 | /**
23 | * Creates parameterless [Event] for given name (protocol domain + event name)
24 | */
25 | internal fun fromFrame(eventFrame: EventResponseFrame) = eventFrame.eventName.split(".", limit = 2, ignoreCase = true).run {
26 | RawEvent(domain = this[0], eventName = this[1], sessionId = eventFrame.sessionId)
27 | }
28 | }
29 | }
30 |
31 | /**
32 | * Represents parameterless [Event] that does not contain any parameters.
33 | */
34 | @Serializable
35 | class RawEvent(
36 | private val domain: String,
37 | private val eventName: String,
38 | private val sessionId: SessionID?
39 | ) : Event {
40 | override fun domain(): String = domain
41 |
42 | override fun eventName(): String = eventName
43 |
44 | fun sessionId(): SessionID? = sessionId
45 |
46 | override fun toString(): String {
47 | return "RawEvent(domain='$domain', eventName='$eventName')"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol
2 |
3 | import io.reactivex.rxjava3.core.Flowable
4 | import io.reactivex.rxjava3.functions.Predicate
5 |
6 | open class Domain(
7 | private val name: String,
8 | private val description: String,
9 | internal val connection: ProtocolConnection
10 | ) {
11 | /**
12 | * Returns domain name.
13 | */
14 | fun name(): String = name
15 |
16 | /**
17 | * Returns domain description.
18 | */
19 | fun description(): String = description
20 |
21 | /**
22 | * Returns flowable capturing all domains events.
23 | */
24 | fun events(): Flowable {
25 | return connection.events().filter {
26 | it.domain() == name
27 | }
28 | }
29 |
30 | /**
31 | * Returns flowable capturing all domains events matching predicate.
32 | */
33 | fun events(filter: Predicate): Flowable {
34 | return connection.events().filter {
35 | it.domain() == name && filter.test(it)
36 | }
37 | }
38 |
39 | /**
40 | * Returns flowable capturing all domain events of a given type.
41 | */
42 | fun events(eventClass: Class): Flowable where T : Event {
43 | return events().ofType(eventClass)
44 | }
45 |
46 | /**
47 | * Returns flowable capturing all domain events of a given type matching predicate.
48 | */
49 | fun events(eventClass: Class, filter: Predicate): Flowable where T : Event {
50 | return events(eventClass).filter(filter)
51 | }
52 |
53 | /**
54 | * Returns domain dependencies.
55 | */
56 | open fun getDependencies(): List = listOf()
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/targets/Target.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.targets
2 |
3 | import pl.wendigo.chrome.api.ProtocolDomains
4 | import pl.wendigo.chrome.api.target.GetTargetInfoRequest
5 | import pl.wendigo.chrome.api.target.TargetID
6 | import pl.wendigo.chrome.api.target.TargetInfo
7 | import pl.wendigo.chrome.protocol.ProtocolConnection
8 | import pl.wendigo.chrome.sync
9 | import java.io.Closeable
10 |
11 | /**
12 | * Represents browser [Target] that can be controlled via DevTools Protocol API
13 | */
14 | class Target(
15 | private val manager: Manager,
16 | private val session: SessionTarget,
17 | connection: ProtocolConnection
18 | ) : ProtocolDomains(connection), AutoCloseable, Closeable {
19 | /**
20 | * Retrieves [TargetInfo] for current target directly from debugger protocol.
21 | */
22 | fun info(): TargetInfo {
23 | return sync(Target.getTargetInfo(GetTargetInfoRequest(session.targetId))).targetInfo
24 | }
25 |
26 | /**
27 | * Closes target releasing all resources on the debugger side.
28 | */
29 | override fun close() {
30 | return manager.close(this)
31 | }
32 |
33 | /**
34 | * Returns target id.
35 | */
36 | fun targetId(): TargetID = session.targetId
37 |
38 | /**
39 | * Returns target session information.
40 | */
41 | fun session(): SessionTarget = session
42 |
43 | /**
44 | * Releases underlying connection.
45 | */
46 | internal fun closeConnection() {
47 | return connection.close()
48 | }
49 |
50 | override fun toString(): String {
51 | return "Target(id='${session.targetId}', sessionId='${session.sessionId}, browserContextId='${session.browserContextID}')"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/generator_templates/protocol_domains.hbs:
--------------------------------------------------------------------------------
1 | package {{Package}}.api
2 |
3 | {{#each Protocol.Domains}}
4 | import {{Package}}.api.{{LowerName}}.{{Name}}Domain
5 | {{/each}}
6 | import {{Package}}.protocol.ProtocolConnection
7 |
8 | /**
9 | * ProtocolDomains represents all domains that can be controlled Chrome via [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/).
10 | *
11 | * @link [https://github.com/chromedevtools/devtools-protocol](https://github.com/chromedevtools/devtools-protocol)
12 | * @link [https://chromedevtools.github.io/devtools-protocol/](https://chromedevtools.github.io/devtools-protocol/)
13 | */
14 | open class ProtocolDomains internal constructor(connection: ProtocolConnection): pl.wendigo.chrome.protocol.Domains("{{ Protocol.Version.Major }}.{{ Protocol.Version.Minor }}", connection) {
15 | {{#each Protocol.Domains}}
16 | /**
17 | * {{#if Description}}{{{Description}}}{{else}}Lazily returns [{{Name}}Domain] domain object allowing to invoke methods on [{{Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Name}}) protocol domain.{{/if}}
18 | *
19 | {{#if Experimental}}
20 | * This API is marked as experimental in protocol definition and can change in the future.
21 | {{/if}}
22 | * @link [https://chromedevtools.github.io/devtools-protocol/tot/{{Name}}](Domain {{Name}} documentation)
23 | */
24 | {{{ Annotations }}}
25 | val {{Name}}: {{Name}}Domain by lazy {
26 | {{Name}}Domain(connection)
27 | }
28 |
29 | {{/each}}
30 |
31 | /**
32 | * Returns a list of all protocol domain objects.
33 | */
34 | fun domains(): List<{{Package}}.protocol.Domain> = listOf(
35 | {{#each Protocol.Domains}}
36 | {{Name}}Domain(connection),
37 | {{/each}}
38 | )
39 | }
--------------------------------------------------------------------------------
/src/samples/kotlin/pl/wendigo/chrome/samples/Containerized.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.samples
2 |
3 | import pl.wendigo.chrome.Browser
4 | import pl.wendigo.chrome.api.network.EnableRequest
5 | import pl.wendigo.chrome.api.page.NavigateRequest
6 | import pl.wendigo.chrome.sync
7 |
8 | object Containerized {
9 | @JvmStatic
10 | fun main(args: Array) {
11 | val browser = Browser
12 | .builder()
13 | .withAddress("127.0.0.1:9222")
14 | .runInDocker(true)
15 | .multiplexConnections(true)
16 | .build()
17 |
18 | browser.target("about:blank").use { target ->
19 | sync(target.Page.enable())
20 | sync(target.DOM.enable())
21 | sync(target.CSS.enable())
22 | sync(target.Network.enable(EnableRequest()))
23 |
24 | browser.events().subscribe {
25 | println("Received browser event $it")
26 | }
27 |
28 | target.events().subscribe {
29 | println("Received target event $it")
30 | }
31 |
32 | sync(
33 | target.Page.navigate(NavigateRequest(url = "https://github.com/wendigo/chrome-reactive-kotlin")).flatMap { (frameId) ->
34 | target.Page.frameStoppedLoading().filter { (loadedFrameId) ->
35 | loadedFrameId == frameId
36 | }.take(1).singleOrError()
37 | }
38 | )
39 |
40 | println("Created target is ${target.targetId()} with session info ${target.session()}")
41 |
42 | browser.targets().forEach {
43 | println("Target ${it.targetId} has url: ${it.url} and browser context id: ${it.browserContextId}")
44 | }
45 |
46 | Thread.sleep(100000)
47 | }
48 |
49 | browser.close()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/websocket/WebSocketFrame.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol.websocket
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonElement
6 | import pl.wendigo.chrome.api.target.SessionID
7 |
8 | /**
9 | * Represents different protocol frame types exchanged over WebSocket connection to the debugger.
10 | */
11 | @Serializable
12 | sealed class WebSocketFrame
13 |
14 | /**
15 | * Frame that is generated in response to method call.
16 | */
17 | interface ResponseFrame {
18 | fun matches(request: RequestFrame): Boolean
19 | }
20 |
21 | /**
22 | * Represents frame carrying event generated by protocol.
23 | */
24 | @Serializable
25 | data class EventResponseFrame(
26 | @SerialName("method")
27 | val eventName: String,
28 | @SerialName("params")
29 | val params: JsonElement,
30 | val sessionId: SessionID? = null
31 | ) : WebSocketFrame() {
32 | fun matches(eventName: String, sessionId: SessionID?): Boolean = this.eventName == eventName && this.sessionId == sessionId
33 | fun matches(sessionId: SessionID?): Boolean = this.sessionId == sessionId
34 | }
35 |
36 | /**
37 | * Represents frame carrying method call error response generated by protocol.
38 | */
39 | @Serializable
40 | data class ErrorResponseFrame(
41 | val id: Long,
42 | val error: RequestError,
43 | val sessionId: SessionID? = null
44 | ) : WebSocketFrame(), ResponseFrame {
45 | override fun matches(request: RequestFrame): Boolean = id == request.id && sessionId == request.sessionId
46 | }
47 |
48 | /**
49 | * Represents frame carrying method call response generated by protocol.
50 | */
51 | @Serializable
52 | data class RequestResponseFrame(
53 | val id: Long,
54 | val result: JsonElement,
55 | val sessionId: SessionID? = null
56 | ) : WebSocketFrame(), ResponseFrame {
57 | override fun matches(request: RequestFrame): Boolean = id == request.id && sessionId == request.sessionId
58 | }
59 |
--------------------------------------------------------------------------------
/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -xeuo pipefail
3 |
4 | GREEN='\033[0;32m'
5 | NC='\033[0m'
6 |
7 | # based on https://github.com/cyrus-and/chrome-remote-interface/blob/master/scripts/update-protocol.sh
8 | # version="master"
9 | version="219a9d66a51e135d96e261ebbe6bf385dc11389b" # pin to version for now
10 | REPOSITORY_PATH="https://${ACCESS_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
11 |
12 | trap "rm -f 'browser_protocol.json' 'js_protocol.json'" EXIT
13 |
14 | base='https://raw.githubusercontent.com/ChromeDevTools/devtools-protocol'
15 | printf "${GREEN}Fetching:\n\t/$version/json/browser_protocol.json...${NC}\n"
16 | curl -s "$base/$version/json/browser_protocol.json" >"browser_protocol.json"
17 | printf "${GREEN}Fetching:\n\t/$version/json/js_protocol.json...${NC}\n"
18 | curl -s "$base/$version/json/js_protocol.json" >"js_protocol.json"
19 |
20 | printf "${GREEN}Merging files js_protocol.json, browser_protocol.json into protocol.json${NC}\n"
21 |
22 | git checkout master
23 |
24 | node -p '
25 | const protocols = process.argv.slice(1).map((path) => JSON.parse(fs.readFileSync(path)));
26 | protocols[0].domains.push(...protocols[1].domains);
27 | JSON.stringify(protocols[0], null, 4);
28 | ' "js_protocol.json" "browser_protocol.json" >protocol.json
29 |
30 | git --no-pager diff protocol.json
31 |
32 | if [[ -n $(git status -s) ]];
33 | then
34 | printf "${GREEN}Regenerating domains...\n${NC}"
35 | go get -u -v github.com/aymerick/raymond
36 | go run generator.go
37 | printf "${GREEN}Formatting result code...\n${NC}"
38 | ./gradlew formatKotlin
39 | printf "${GREEN}Checking if code is formatted...\n${NC}"
40 | ./gradlew lintKotlin
41 | printf "${GREEN}Commiting changes...\n${NC}"
42 | git config --global user.name 'Mateusz Gajewski' && git config --global user.email 'mateusz.gajewski@gmail.com'
43 | git add .
44 | git commit -m "Automatically updated to newest protocol"
45 | git push $REPOSITORY_PATH master
46 | printf "${GREEN}All done!\n${NC}"
47 |
48 | else
49 | printf "${GREEN}No changes to the protocol.\n${NC}"
50 | fi
51 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/log/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.log
2 |
3 | /**
4 | * Log entry.
5 | *
6 | * @link [Log#LogEntry](https://chromedevtools.github.io/devtools-protocol/tot/Log#type-LogEntry) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class LogEntry(
11 | /**
12 | * Log entry source.
13 | */
14 | val source: String,
15 |
16 | /**
17 | * Log entry severity.
18 | */
19 | val level: String,
20 |
21 | /**
22 | * Logged text.
23 | */
24 | val text: String,
25 |
26 | /**
27 | * Timestamp when this entry was added.
28 | */
29 | val timestamp: pl.wendigo.chrome.api.runtime.Timestamp,
30 |
31 | /**
32 | * URL of the resource if known.
33 | */
34 | val url: String? = null,
35 |
36 | /**
37 | * Line number in the resource.
38 | */
39 | val lineNumber: Int? = null,
40 |
41 | /**
42 | * JavaScript stack trace.
43 | */
44 | val stackTrace: pl.wendigo.chrome.api.runtime.StackTrace? = null,
45 |
46 | /**
47 | * Identifier of the network request associated with this entry.
48 | */
49 | val networkRequestId: pl.wendigo.chrome.api.network.RequestId? = null,
50 |
51 | /**
52 | * Identifier of the worker associated with this entry.
53 | */
54 | val workerId: String? = null,
55 |
56 | /**
57 | * Call arguments.
58 | */
59 | val args: List? = null
60 | )
61 |
62 | /**
63 | * Violation configuration setting.
64 | *
65 | * @link [Log#ViolationSetting](https://chromedevtools.github.io/devtools-protocol/tot/Log#type-ViolationSetting) type documentation.
66 | */
67 |
68 | @kotlinx.serialization.Serializable
69 | data class ViolationSetting(
70 | /**
71 | * Violation type.
72 | */
73 | val name: String,
74 |
75 | /**
76 | * Time threshold to trigger upon.
77 | */
78 | val threshold: Double
79 | )
80 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/applicationcache/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.applicationcache
2 |
3 | /**
4 | * Detailed application cache resource information.
5 | *
6 | * @link [ApplicationCache#ApplicationCacheResource](https://chromedevtools.github.io/devtools-protocol/tot/ApplicationCache#type-ApplicationCacheResource) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class ApplicationCacheResource(
11 | /**
12 | * Resource url.
13 | */
14 | val url: String,
15 |
16 | /**
17 | * Resource size.
18 | */
19 | val size: Int,
20 |
21 | /**
22 | * Resource type.
23 | */
24 | val type: String
25 | )
26 |
27 | /**
28 | * Detailed application cache information.
29 | *
30 | * @link [ApplicationCache#ApplicationCache](https://chromedevtools.github.io/devtools-protocol/tot/ApplicationCache#type-ApplicationCache) type documentation.
31 | */
32 |
33 | @kotlinx.serialization.Serializable
34 | data class ApplicationCache(
35 | /**
36 | * Manifest URL.
37 | */
38 | val manifestURL: String,
39 |
40 | /**
41 | * Application cache size.
42 | */
43 | val size: Double,
44 |
45 | /**
46 | * Application cache creation time.
47 | */
48 | val creationTime: Double,
49 |
50 | /**
51 | * Application cache update time.
52 | */
53 | val updateTime: Double,
54 |
55 | /**
56 | * Application cache resources.
57 | */
58 | val resources: List
59 | )
60 |
61 | /**
62 | * Frame identifier - manifest URL pair.
63 | *
64 | * @link [ApplicationCache#FrameWithManifest](https://chromedevtools.github.io/devtools-protocol/tot/ApplicationCache#type-FrameWithManifest) type documentation.
65 | */
66 |
67 | @kotlinx.serialization.Serializable
68 | data class FrameWithManifest(
69 | /**
70 | * Frame identifier.
71 | */
72 | val frameId: pl.wendigo.chrome.api.page.FrameId,
73 |
74 | /**
75 | * Manifest URL.
76 | */
77 | val manifestURL: String,
78 |
79 | /**
80 | * Application cache status.
81 | */
82 | val status: Int
83 | )
84 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/storage/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.storage
2 |
3 | /**
4 | * Enum of possible storage types.
5 | *
6 | * @link [Storage#StorageType](https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-StorageType) type documentation.
7 | */
8 | @kotlinx.serialization.Serializable
9 | enum class StorageType {
10 | @kotlinx.serialization.SerialName("appcache")
11 | APPCACHE,
12 |
13 | @kotlinx.serialization.SerialName("cookies")
14 | COOKIES,
15 |
16 | @kotlinx.serialization.SerialName("file_systems")
17 | FILE_SYSTEMS,
18 |
19 | @kotlinx.serialization.SerialName("indexeddb")
20 | INDEXEDDB,
21 |
22 | @kotlinx.serialization.SerialName("local_storage")
23 | LOCAL_STORAGE,
24 |
25 | @kotlinx.serialization.SerialName("shader_cache")
26 | SHADER_CACHE,
27 |
28 | @kotlinx.serialization.SerialName("websql")
29 | WEBSQL,
30 |
31 | @kotlinx.serialization.SerialName("service_workers")
32 | SERVICE_WORKERS,
33 |
34 | @kotlinx.serialization.SerialName("cache_storage")
35 | CACHE_STORAGE,
36 |
37 | @kotlinx.serialization.SerialName("all")
38 | ALL,
39 |
40 | @kotlinx.serialization.SerialName("other")
41 | OTHER;
42 | }
43 |
44 | /**
45 | * Usage for a storage type.
46 | *
47 | * @link [Storage#UsageForType](https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-UsageForType) type documentation.
48 | */
49 |
50 | @kotlinx.serialization.Serializable
51 | data class UsageForType(
52 | /**
53 | * Name of storage type.
54 | */
55 | val storageType: StorageType,
56 |
57 | /**
58 | * Storage usage (bytes).
59 | */
60 | val usage: Double
61 | )
62 |
63 | /**
64 | * Pair of issuer origin and number of available (signed, but not used) Trust
65 | Tokens from that issuer.
66 | *
67 | * @link [Storage#TrustTokens](https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-TrustTokens) type documentation.
68 | */
69 |
70 | @kotlinx.serialization.Serializable
71 | data class TrustTokens(
72 | /**
73 | *
74 | */
75 | val issuerOrigin: String,
76 |
77 | /**
78 | *
79 | */
80 | val count: Double
81 | )
82 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/target/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.target
2 |
3 | /**
4 | *
5 | *
6 | * @link [Target#TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target#type-TargetID) type documentation.
7 | */
8 |
9 | typealias TargetID = String
10 |
11 | /**
12 | * Unique identifier of attached debugging session.
13 | *
14 | * @link [Target#SessionID](https://chromedevtools.github.io/devtools-protocol/tot/Target#type-SessionID) type documentation.
15 | */
16 |
17 | typealias SessionID = String
18 |
19 | /**
20 | *
21 | *
22 | * @link [Target#TargetInfo](https://chromedevtools.github.io/devtools-protocol/tot/Target#type-TargetInfo) type documentation.
23 | */
24 |
25 | @kotlinx.serialization.Serializable
26 | data class TargetInfo(
27 | /**
28 | *
29 | */
30 | val targetId: TargetID,
31 |
32 | /**
33 | *
34 | */
35 | val type: String,
36 |
37 | /**
38 | *
39 | */
40 | val title: String,
41 |
42 | /**
43 | *
44 | */
45 | val url: String,
46 |
47 | /**
48 | * Whether the target has an attached client.
49 | */
50 | val attached: Boolean,
51 |
52 | /**
53 | * Opener target Id
54 | */
55 | val openerId: TargetID? = null,
56 |
57 | /**
58 | * Whether the target has access to the originating window.
59 | */
60 | @pl.wendigo.chrome.protocol.Experimental val canAccessOpener: Boolean,
61 |
62 | /**
63 | * Frame id of originating window (is only set if target has an opener).
64 | */
65 | @pl.wendigo.chrome.protocol.Experimental val openerFrameId: pl.wendigo.chrome.api.page.FrameId? = null,
66 |
67 | /**
68 | *
69 | */
70 | @pl.wendigo.chrome.protocol.Experimental val browserContextId: pl.wendigo.chrome.api.browser.BrowserContextID? = null
71 | )
72 |
73 | /**
74 | *
75 | *
76 | * @link [Target#RemoteLocation](https://chromedevtools.github.io/devtools-protocol/tot/Target#type-RemoteLocation) type documentation.
77 | */
78 |
79 | @kotlinx.serialization.Serializable
80 | data class RemoteLocation(
81 | /**
82 | *
83 | */
84 | val host: String,
85 |
86 | /**
87 | *
88 | */
89 | val port: Int
90 | )
91 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/memory/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.memory
2 |
3 | /**
4 | * Memory pressure level.
5 | *
6 | * @link [Memory#PressureLevel](https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-PressureLevel) type documentation.
7 | */
8 | @kotlinx.serialization.Serializable
9 | enum class PressureLevel {
10 | @kotlinx.serialization.SerialName("moderate")
11 | MODERATE,
12 |
13 | @kotlinx.serialization.SerialName("critical")
14 | CRITICAL;
15 | }
16 |
17 | /**
18 | * Heap profile sample.
19 | *
20 | * @link [Memory#SamplingProfileNode](https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-SamplingProfileNode) type documentation.
21 | */
22 |
23 | @kotlinx.serialization.Serializable
24 | data class SamplingProfileNode(
25 | /**
26 | * Size of the sampled allocation.
27 | */
28 | val size: Double,
29 |
30 | /**
31 | * Total bytes attributed to this sample.
32 | */
33 | val total: Double,
34 |
35 | /**
36 | * Execution stack at the point of allocation.
37 | */
38 | val stack: List
39 | )
40 |
41 | /**
42 | * Array of heap profile samples.
43 | *
44 | * @link [Memory#SamplingProfile](https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-SamplingProfile) type documentation.
45 | */
46 |
47 | @kotlinx.serialization.Serializable
48 | data class SamplingProfile(
49 | /**
50 | *
51 | */
52 | val samples: List,
53 |
54 | /**
55 | *
56 | */
57 | val modules: List
58 | )
59 |
60 | /**
61 | * Executable module information
62 | *
63 | * @link [Memory#Module](https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-Module) type documentation.
64 | */
65 |
66 | @kotlinx.serialization.Serializable
67 | data class Module(
68 | /**
69 | * Name of the module.
70 | */
71 | val name: String,
72 |
73 | /**
74 | * UUID of the module.
75 | */
76 | val uuid: String,
77 |
78 | /**
79 | * Base address where the module is loaded into memory. Encoded as a decimal
80 | or hexadecimal (0x prefixed) string.
81 | */
82 | val baseAddress: String,
83 |
84 | /**
85 | * Size of the module in bytes.
86 | */
87 | val size: Double
88 | )
89 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/ContainerizedBrowser.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome
2 |
3 | import org.slf4j.Logger
4 | import org.slf4j.LoggerFactory
5 | import org.testcontainers.utility.DockerImageName
6 | import pl.wendigo.chrome.api.ProtocolDomains
7 | import pl.wendigo.chrome.protocol.ProtocolConnection
8 | import pl.wendigo.chrome.targets.Manager
9 |
10 | internal class ContainerizedBrowser private constructor(
11 | private val container: HeadlessChromeContainer,
12 | browserInfo: BrowserInfo,
13 | options: Options,
14 | connection: ProtocolConnection,
15 | manager: Manager
16 | ) : pl.wendigo.chrome.Browser(browserInfo, options, connection, manager) {
17 | override fun close() {
18 | super.close()
19 |
20 | logger.info("Stopping container {}", container.containerId)
21 | container.close()
22 | }
23 |
24 | override fun toString(): String {
25 | return "ContainerizedBrowser(container=${container.dockerImageName}[${container.containerId}])"
26 | }
27 |
28 | companion object {
29 |
30 | private val logger: Logger = LoggerFactory.getLogger(ContainerizedBrowser::class.java)
31 |
32 | /**
33 | * Creates new Browser instance by connecting to remote chrome debugger.
34 | */
35 | internal fun connect(dockerImageName: DockerImageName, options: Options): Browser {
36 | logger.info("Creating new headless Chrome instance from image {}", dockerImageName)
37 | val container = HeadlessChromeContainer(dockerImageName)
38 | container.start()
39 |
40 | logger.info("Started container {}", container.containerId)
41 | logger.info("Debugger is available on http://{}", container.getBrowserEndpoint())
42 |
43 | val info = fetchInfo(container.getBrowserEndpoint())
44 |
45 | val connection = ProtocolConnection.open(info.webSocketDebuggerUrl, options.eventsBufferSize)
46 | val protocol = ProtocolDomains(connection)
47 |
48 | return ContainerizedBrowser(
49 | container,
50 | info,
51 | options,
52 | connection,
53 | Manager(
54 | info.webSocketDebuggerUrl,
55 | options.multiplexConnections,
56 | options.eventsBufferSize,
57 | protocol
58 | )
59 | )
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/package.md:
--------------------------------------------------------------------------------
1 | # Module Chrome Reactive Kotlin
2 |
3 | chrome-reactive-kotlin is a low level Chrome DevTools Protocol client written in Kotlin and leveraging RxJava3 for easy composability.
4 |
5 | Library exposes all protocol [pl.wendigo.chrome.api.ProtocolDomains] in a single, cohesive and highly composable API. It supports both headless and non-headless Chrome automation capabilities.
6 |
7 | # Package pl.wendigo.chrome
8 |
9 | Contains library main entrypoint class ([Browser]) responsible for connecting to remote headless Chrome instance, creating and managing targets (web pages).
10 |
11 | [Browser] object can be obtained using [Browser.Builder]. Then [Target]s can be created using [Browser.target] method.
12 |
13 | @sample pl.wendigo.chrome.samples.CreateNewTarget.main
14 | @sample pl.wendigo.chrome.samples.CreateBrowser.main
15 |
16 | # Package pl.wendigo.chrome.protocol
17 |
18 | Contains DevTools protocol representation classes:
19 |
20 | * [ProtocolConnection] is a class responsible for sending and receiving protocol responses and events over [WebsocketFramesStream]
21 | * [Event] is a parent class of all events that are generated by protocol
22 | * [RawEvent] represents an event that is parameterless
23 | * [Domain] is parent class of all protocol domain classes
24 | * [Domains] is parent class representing whole protocol with all [Domain]s
25 |
26 | # Package pl.wendigo.chrome.protocol.websocket
27 |
28 | Contains DevTools protocol WebSocket primitives and utility classes:
29 |
30 | * [WebSocketFramesStream] represents stream of frames that are exchanged between protocol client and the browser over the WebSocket connection
31 | * [RequestFrame] represents frame that is sent over the WebSocket connection
32 | * [ResponseFrame] represents different frame types that are received over the WebSocket connection:
33 | * [ErrorResponseFrame] represents error frame that is received if the request is malformed and/or invalid
34 | * [RequestResponseFrame] represents response frame that is received when request was fulfilled successfully
35 | * [EventResponseFrame] represents event frame that is received when [Domain] event is generated
36 |
37 |
38 | # Package pl.wendigo.chrome.targets
39 |
40 | Targets management related classes ([Manager], [SessionTarget], [Target])
41 |
42 | # Package pl.wendigo.chrome.api
43 |
44 | Contains auto-generated definitions of domains with methods, events, types.
45 |
46 | [ProtocolDomains] is a class that is used to retrieve protocol's domain objects.
--------------------------------------------------------------------------------
/.github/workflows/release-to-ossrh.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Release to OSSRH
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | branch:
7 | description: "Release branch and/or tag"
8 | default: "master"
9 | required: true
10 | version:
11 | description: "Mark next version"
12 | default: ""
13 | required: false
14 |
15 | jobs:
16 | test:
17 | name: "Test and release to Sonatype"
18 | runs-on: ubuntu-latest
19 | env:
20 | GRADLE_OPTS: "-Xmx8198m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError"
21 | GRADLE_FLAGS: "--no-daemon -i"
22 | SIGNING_KEY_ID: "${{ secrets.SIGNING_KEY_ID }}"
23 | SIGNING_KEY: "${{ secrets.SIGNING_KEY }}"
24 | SIGNING_KEY_PASSWORD: "${{ secrets.SIGNING_PASSWORD }}"
25 | SONATYPE_USERNAME: "${{ secrets.SONATYPE_USER }}"
26 | SONATYPE_PASSWORD: "${{ secrets.SONATYPE_PASSWORD }}"
27 | GITHUB_TOKEN: "${{ secrets.ACCESS_TOKEN }}"
28 |
29 | steps:
30 | - name: Checkout code
31 | uses: actions/checkout@v2
32 | with:
33 | ref: ${{ github.event.inputs.branch }}
34 | fetch-depth: 0
35 |
36 | - name: Set up Java 11
37 | uses: actions/setup-java@v1
38 | with:
39 | java-version: 11
40 |
41 | - name: Cache Gradle dependencies
42 | uses: actions/cache@v2
43 | with:
44 | path: |
45 | ~/.gradle/caches
46 | ~/.gradle/wrapper
47 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
48 | restore-keys: |
49 | ${{ runner.os }}-gradle-
50 |
51 | - name: Tests
52 | run: ./gradlew clean test ${GRADLE_FLAGS}
53 |
54 | - name: Display current version
55 | run: ./gradlew currentVersion
56 |
57 | - name: Release artefacts with forced version
58 | run: ./gradlew release ${GRADLE_FLAGS} -Prelease.forceVersion=${{ github.event.inputs.version }}
59 | if: github.event.inputs.version != ''
60 |
61 | - name: Release artefacts
62 | run: ./gradlew release ${GRADLE_FLAGS}
63 | if: github.event.inputs.version == ''
64 |
65 | - name: Display released version
66 | run: ./gradlew currentVersion
67 |
68 | - name: Publish to Sonatype
69 | run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository ${GRADLE_FLAGS}
70 |
71 | - name: Publish to Github Packages
72 | run: ./gradlew publishAllPublicationsToGithubRepository ${GRADLE_FLAGS}
73 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/heapprofiler/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.heapprofiler
2 |
3 | /**
4 | * Heap snapshot object id.
5 | *
6 | * @link [HeapProfiler#HeapSnapshotObjectId](https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-HeapSnapshotObjectId) type documentation.
7 | */
8 |
9 | typealias HeapSnapshotObjectId = String
10 |
11 | /**
12 | * Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes.
13 | *
14 | * @link [HeapProfiler#SamplingHeapProfileNode](https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-SamplingHeapProfileNode) type documentation.
15 | */
16 |
17 | @kotlinx.serialization.Serializable
18 | data class SamplingHeapProfileNode(
19 | /**
20 | * Function location.
21 | */
22 | val callFrame: pl.wendigo.chrome.api.runtime.CallFrame,
23 |
24 | /**
25 | * Allocations size in bytes for the node excluding children.
26 | */
27 | val selfSize: Double,
28 |
29 | /**
30 | * Node id. Ids are unique across all profiles collected between startSampling and stopSampling.
31 | */
32 | val id: Int,
33 |
34 | /**
35 | * Child nodes.
36 | */
37 | val children: List
38 | )
39 |
40 | /**
41 | * A single sample from a sampling profile.
42 | *
43 | * @link [HeapProfiler#SamplingHeapProfileSample](https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-SamplingHeapProfileSample) type documentation.
44 | */
45 |
46 | @kotlinx.serialization.Serializable
47 | data class SamplingHeapProfileSample(
48 | /**
49 | * Allocation size in bytes attributed to the sample.
50 | */
51 | val size: Double,
52 |
53 | /**
54 | * Id of the corresponding profile tree node.
55 | */
56 | val nodeId: Int,
57 |
58 | /**
59 | * Time-ordered sample ordinal number. It is unique across all profiles retrieved
60 | between startSampling and stopSampling.
61 | */
62 | val ordinal: Double
63 | )
64 |
65 | /**
66 | * Sampling profile.
67 | *
68 | * @link [HeapProfiler#SamplingHeapProfile](https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-SamplingHeapProfile) type documentation.
69 | */
70 |
71 | @kotlinx.serialization.Serializable
72 | data class SamplingHeapProfile(
73 | /**
74 | *
75 | */
76 | val head: SamplingHeapProfileNode,
77 |
78 | /**
79 | *
80 | */
81 | val samples: List
82 | )
83 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '18 3 * * 2'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 |
28 | strategy:
29 | fail-fast: false
30 | matrix:
31 | language: [ 'java' ]
32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
33 | # Learn more:
34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
35 |
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v2
39 |
40 | # Initializes the CodeQL tools for scanning.
41 | - name: Initialize CodeQL
42 | uses: github/codeql-action/init@v1
43 | with:
44 | languages: ${{ matrix.language }}
45 | # If you wish to specify custom queries, you can do so here or in a config file.
46 | # By default, queries listed here will override any specified in a config file.
47 | # Prefix the list here with "+" to use these queries and those in the config file.
48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
49 |
50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
51 | # If this step fails, then you should remove it and run the build manually (see below)
52 | - name: Autobuild
53 | uses: github/codeql-action/autobuild@v1
54 |
55 | # ℹ️ Command-line programs to run using the OS shell.
56 | # 📚 https://git.io/JvXDl
57 |
58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
59 | # and modify them (or add more) to build your code if your project
60 | # uses a compiled language
61 |
62 | #- run: |
63 | # make bootstrap
64 | # make release
65 |
66 | - name: Perform CodeQL Analysis
67 | uses: github/codeql-action/analyze@v1
68 |
--------------------------------------------------------------------------------
/generator_templates/protocol_domain.hbs:
--------------------------------------------------------------------------------
1 | package {{Package}}.api.{{Domain.LowerName}}
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | *{{#if Domain.Description}}{{{trim Domain.Description}}}{{else}} {{Domain.Name}}Domain represents {{Domain.Name}} protocol domain request/response operations and events that can be captured.{{/if}}
7 | *
8 | {{#if Domain.Experimental}}
9 | * This API is marked as experimental in protocol definition and can change in the future.
10 | {{/if}}
11 | * @link Protocol [{{Domain.Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain.Name}}) domain documentation.
12 | */
13 | {{{ Domain.Annotations }}}
14 | class {{Domain.Name}}Domain internal constructor(connection : {{Package}}.protocol.ProtocolConnection)
15 | {{{ Domain.Interfaces }}}
16 | {
17 | {{#each Domain.Commands}}
18 | /**
19 | *{{{trim Description}}}
20 | *
21 | * @link Protocol [{{Domain.Name}}#{{Name}}](https://chromedevtools.github.io/devtools-protocol/tot/{{Domain.Name}}#method-{{Name}}) method documentation.
22 | */
23 | {{{ Annotations }}}
24 | {{{ MethodModifiers }}} fun {{Name}}({{#if HasInputParams}}input: {{SimpleName}}Request{{/if}}): io.reactivex.rxjava3.core.Single<{{#if HasReturnValue}}{{ClassName}}{{else}}{{Package}}.protocol.websocket.RequestResponseFrame{{/if}}> = connection.request("{{Domain}}.{{Name}}", {{#if HasInputParams}}Json.encodeToJsonElement({{SimpleName}}Request.serializer(), input){{else}}null{{/if}}, {{#if HasReturnValue}}{{ClassName}}{{else}}{{Package}}.protocol.websocket.RequestResponseFrame{{/if}}.serializer())
25 | {{/each}}
26 | {{#each Domain.Events}}
27 | /**
28 | * {{#if Description}}{{{trim Description}}}{{else}} Returns observable capturing all {{Domain.Name}}.{{Name}} events.{{/if}}
29 | */
30 | fun {{Name}}(): io.reactivex.rxjava3.core.Flowable<{{#if HasReturnValue}}{{ClassName}}{{else}}{{Package}}.protocol.RawEvent{{/if}}> = connection.events("{{Domain.Name}}.{{Name}}", {{#if HasReturnValue}}{{ClassName}}{{else}}{{Package}}.protocol.RawEvent{{/if}}.serializer())
31 | {{/each}}
32 |
33 | {{#if Domain.Dependencies }}
34 | /**
35 | * Returns list of dependant domains that should be enabled prior to enabling this domain.
36 | */
37 | override fun getDependencies(): List<{{ Package }}.protocol.Domain> {
38 | return arrayListOf(
39 | {{#each Domain.Dependencies}}
40 | {{ Package }}.api.{{ lower . }}.{{.}}Domain(connection),
41 | {{/each}}
42 | )
43 | }
44 | {{/if}}
45 | }
46 | {{#each Domain.Commands}}
47 | {{{InputDataClass}}}
48 | {{{OutputDataClass}}}
49 | {{/each}}
50 | {{#each Domain.Events}}
51 | {{{OutputDataClass}}}
52 | {{/each}}
53 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/domdebugger/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.domdebugger
2 |
3 | /**
4 | * DOM breakpoint type.
5 | *
6 | * @link [DOMDebugger#DOMBreakpointType](https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#type-DOMBreakpointType) type documentation.
7 | */
8 | @kotlinx.serialization.Serializable
9 | enum class DOMBreakpointType {
10 | @kotlinx.serialization.SerialName("subtree-modified")
11 | SUBTREE_MODIFIED,
12 |
13 | @kotlinx.serialization.SerialName("attribute-modified")
14 | ATTRIBUTE_MODIFIED,
15 |
16 | @kotlinx.serialization.SerialName("node-removed")
17 | NODE_REMOVED;
18 | }
19 |
20 | /**
21 | * CSP Violation type.
22 | *
23 | * @link [DOMDebugger#CSPViolationType](https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#type-CSPViolationType) type documentation.
24 | */
25 | @kotlinx.serialization.Serializable
26 | enum class CSPViolationType {
27 | @kotlinx.serialization.SerialName("trustedtype-sink-violation")
28 | TRUSTEDTYPE_SINK_VIOLATION,
29 |
30 | @kotlinx.serialization.SerialName("trustedtype-policy-violation")
31 | TRUSTEDTYPE_POLICY_VIOLATION;
32 | }
33 |
34 | /**
35 | * Object event listener.
36 | *
37 | * @link [DOMDebugger#EventListener](https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#type-EventListener) type documentation.
38 | */
39 |
40 | @kotlinx.serialization.Serializable
41 | data class EventListener(
42 | /**
43 | * `EventListener`'s type.
44 | */
45 | val type: String,
46 |
47 | /**
48 | * `EventListener`'s useCapture.
49 | */
50 | val useCapture: Boolean,
51 |
52 | /**
53 | * `EventListener`'s passive flag.
54 | */
55 | val passive: Boolean,
56 |
57 | /**
58 | * `EventListener`'s once flag.
59 | */
60 | val once: Boolean,
61 |
62 | /**
63 | * Script id of the handler code.
64 | */
65 | val scriptId: pl.wendigo.chrome.api.runtime.ScriptId,
66 |
67 | /**
68 | * Line number in the script (0-based).
69 | */
70 | val lineNumber: Int,
71 |
72 | /**
73 | * Column number in the script (0-based).
74 | */
75 | val columnNumber: Int,
76 |
77 | /**
78 | * Event handler function value.
79 | */
80 | val handler: pl.wendigo.chrome.api.runtime.RemoteObject? = null,
81 |
82 | /**
83 | * Event original handler function value.
84 | */
85 | val originalHandler: pl.wendigo.chrome.api.runtime.RemoteObject? = null,
86 |
87 | /**
88 | * Node the listener is added to (if any).
89 | */
90 | val backendNodeId: pl.wendigo.chrome.api.dom.BackendNodeId? = null
91 | )
92 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/backgroundservice/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.backgroundservice
2 |
3 | /**
4 | * The Background Service that will be associated with the commands/events.
5 | Every Background Service operates independently, but they share the same
6 | API.
7 | *
8 | * @link [BackgroundService#ServiceName](https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#type-ServiceName) type documentation.
9 | */
10 | @kotlinx.serialization.Serializable
11 | enum class ServiceName {
12 | @kotlinx.serialization.SerialName("backgroundFetch")
13 | BACKGROUNDFETCH,
14 |
15 | @kotlinx.serialization.SerialName("backgroundSync")
16 | BACKGROUNDSYNC,
17 |
18 | @kotlinx.serialization.SerialName("pushMessaging")
19 | PUSHMESSAGING,
20 |
21 | @kotlinx.serialization.SerialName("notifications")
22 | NOTIFICATIONS,
23 |
24 | @kotlinx.serialization.SerialName("paymentHandler")
25 | PAYMENTHANDLER,
26 |
27 | @kotlinx.serialization.SerialName("periodicBackgroundSync")
28 | PERIODICBACKGROUNDSYNC;
29 | }
30 |
31 | /**
32 | * A key-value pair for additional event information to pass along.
33 | *
34 | * @link [BackgroundService#EventMetadata](https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#type-EventMetadata) type documentation.
35 | */
36 |
37 | @kotlinx.serialization.Serializable
38 | data class EventMetadata(
39 | /**
40 | *
41 | */
42 | val key: String,
43 |
44 | /**
45 | *
46 | */
47 | val value: String
48 | )
49 |
50 | /**
51 | *
52 | *
53 | * @link [BackgroundService#BackgroundServiceEvent](https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#type-BackgroundServiceEvent) type documentation.
54 | */
55 |
56 | @kotlinx.serialization.Serializable
57 | data class BackgroundServiceEvent(
58 | /**
59 | * Timestamp of the event (in seconds).
60 | */
61 | val timestamp: pl.wendigo.chrome.api.network.TimeSinceEpoch,
62 |
63 | /**
64 | * The origin this event belongs to.
65 | */
66 | val origin: String,
67 |
68 | /**
69 | * The Service Worker ID that initiated the event.
70 | */
71 | val serviceWorkerRegistrationId: pl.wendigo.chrome.api.serviceworker.RegistrationID,
72 |
73 | /**
74 | * The Background Service this event belongs to.
75 | */
76 | val service: ServiceName,
77 |
78 | /**
79 | * A description of the event.
80 | */
81 | val eventName: String,
82 |
83 | /**
84 | * An identifier that groups related events together.
85 | */
86 | val instanceId: String,
87 |
88 | /**
89 | * A list of event-specific information.
90 | */
91 | val eventMetadata: List
92 | )
93 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/deviceorientation/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.deviceorientation
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * DeviceOrientationDomain represents DeviceOrientation protocol domain request/response operations and events that can be captured.
7 | *
8 | * This API is marked as experimental in protocol definition and can change in the future.
9 | * @link Protocol [DeviceOrientation](https://chromedevtools.github.io/devtools-protocol/tot/DeviceOrientation) domain documentation.
10 | */
11 | @pl.wendigo.chrome.protocol.Experimental
12 | class DeviceOrientationDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
13 | pl.wendigo.chrome.protocol.Domain("DeviceOrientation", """""", connection) {
14 | /**
15 | * Clears the overridden Device Orientation.
16 | *
17 | * @link Protocol [DeviceOrientation#clearDeviceOrientationOverride](https://chromedevtools.github.io/devtools-protocol/tot/DeviceOrientation#method-clearDeviceOrientationOverride) method documentation.
18 | */
19 |
20 | fun clearDeviceOrientationOverride(): io.reactivex.rxjava3.core.Single = connection.request("DeviceOrientation.clearDeviceOrientationOverride", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
21 |
22 | /**
23 | * Overrides the Device Orientation.
24 | *
25 | * @link Protocol [DeviceOrientation#setDeviceOrientationOverride](https://chromedevtools.github.io/devtools-protocol/tot/DeviceOrientation#method-setDeviceOrientationOverride) method documentation.
26 | */
27 |
28 | fun setDeviceOrientationOverride(input: SetDeviceOrientationOverrideRequest): io.reactivex.rxjava3.core.Single = connection.request("DeviceOrientation.setDeviceOrientationOverride", Json.encodeToJsonElement(SetDeviceOrientationOverrideRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
29 | }
30 |
31 | /**
32 | * Represents request frame that can be used with [DeviceOrientation#setDeviceOrientationOverride](https://chromedevtools.github.io/devtools-protocol/tot/DeviceOrientation#method-setDeviceOrientationOverride) operation call.
33 | *
34 | * Overrides the Device Orientation.
35 | * @link [DeviceOrientation#setDeviceOrientationOverride](https://chromedevtools.github.io/devtools-protocol/tot/DeviceOrientation#method-setDeviceOrientationOverride) method documentation.
36 | * @see [DeviceOrientationDomain.setDeviceOrientationOverride]
37 | */
38 | @kotlinx.serialization.Serializable
39 | data class SetDeviceOrientationOverrideRequest(
40 | /**
41 | * Mock alpha
42 | */
43 | val alpha: Double,
44 |
45 | /**
46 | * Mock beta
47 | */
48 | val beta: Double,
49 |
50 | /**
51 | * Mock gamma
52 | */
53 | val gamma: Double
54 |
55 | )
56 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/inspector/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.inspector
2 |
3 | /**
4 | * InspectorDomain represents Inspector protocol domain request/response operations and events that can be captured.
5 | *
6 | * This API is marked as experimental in protocol definition and can change in the future.
7 | * @link Protocol [Inspector](https://chromedevtools.github.io/devtools-protocol/tot/Inspector) domain documentation.
8 | */
9 | @pl.wendigo.chrome.protocol.Experimental
10 | class InspectorDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
11 | pl.wendigo.chrome.protocol.Domain("Inspector", """""", connection) {
12 | /**
13 | * Disables inspector domain notifications.
14 | *
15 | * @link Protocol [Inspector#disable](https://chromedevtools.github.io/devtools-protocol/tot/Inspector#method-disable) method documentation.
16 | */
17 |
18 | fun disable(): io.reactivex.rxjava3.core.Single = connection.request("Inspector.disable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
19 |
20 | /**
21 | * Enables inspector domain notifications.
22 | *
23 | * @link Protocol [Inspector#enable](https://chromedevtools.github.io/devtools-protocol/tot/Inspector#method-enable) method documentation.
24 | */
25 |
26 | fun enable(): io.reactivex.rxjava3.core.Single = connection.request("Inspector.enable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
27 |
28 | /**
29 | * Fired when remote debugging connection is about to be terminated. Contains detach reason.
30 | */
31 | fun detached(): io.reactivex.rxjava3.core.Flowable = connection.events("Inspector.detached", DetachedEvent.serializer())
32 |
33 | /**
34 | * Fired when debugging target has crashed
35 | */
36 | fun targetCrashed(): io.reactivex.rxjava3.core.Flowable = connection.events("Inspector.targetCrashed", pl.wendigo.chrome.protocol.RawEvent.serializer())
37 |
38 | /**
39 | * Fired when debugging target has reloaded after crash
40 | */
41 | fun targetReloadedAfterCrash(): io.reactivex.rxjava3.core.Flowable = connection.events("Inspector.targetReloadedAfterCrash", pl.wendigo.chrome.protocol.RawEvent.serializer())
42 | }
43 |
44 | /**
45 | * Fired when remote debugging connection is about to be terminated. Contains detach reason.
46 | *
47 | * @link [Inspector#detached](https://chromedevtools.github.io/devtools-protocol/tot/Inspector#event-detached) event documentation.
48 | */
49 | @kotlinx.serialization.Serializable
50 | data class DetachedEvent(
51 | /**
52 | * The reason why connection has been terminated.
53 | */
54 | val reason: String
55 |
56 | ) : pl.wendigo.chrome.protocol.Event {
57 | override fun domain() = "Inspector"
58 | override fun eventName() = "detached"
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/websocket/FrameMapper.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol.websocket
2 |
3 | import kotlinx.serialization.KSerializer
4 | import kotlinx.serialization.encodeToString
5 | import kotlinx.serialization.json.Json
6 | import kotlinx.serialization.json.JsonContentPolymorphicSerializer
7 | import kotlinx.serialization.json.JsonElement
8 | import kotlinx.serialization.json.jsonObject
9 | import pl.wendigo.chrome.protocol.DeserializationFailed
10 | import pl.wendigo.chrome.protocol.RequestFailed
11 | import pl.wendigo.chrome.protocol.SerializationFailed
12 |
13 | /**
14 | * FrameMapper is responsible for (de)serializing frames exchanged via Chrome's [DevTool Protocol](https://chromedevtools.github.io/devtools-protocol/).
15 | */
16 | class FrameMapper {
17 | /**
18 | * Serializes request frame using internal object mapper
19 | */
20 | fun serialize(requestFrame: RequestFrame): String {
21 | return try {
22 | Json.encodeToString(requestFrame)
23 | } catch (e: Exception) {
24 | throw SerializationFailed("Could not serialize request frame", e)
25 | }
26 | }
27 |
28 | /**
29 | * Deserialize [ResponseFrame] as concrete type.
30 | */
31 | internal fun deserializeResponseFrame(request: RequestFrame, response: ResponseFrame, serializer: KSerializer): T {
32 | when (response) {
33 | is ErrorResponseFrame -> throw RequestFailed(request, response.error.message)
34 | is RequestResponseFrame -> try {
35 | if (serializer == RequestResponseFrame.serializer()) {
36 | @Suppress("UNCHECKED_CAST")
37 | return response as T
38 | } else {
39 | return Json.decodeFromJsonElement(serializer, response.result)
40 | }
41 | } catch (ex: Exception) {
42 | throw DeserializationFailed("Could not deserialize response frame", ex)
43 | }
44 | else -> throw RuntimeException("Unrecognized response type $response")
45 | }
46 | }
47 |
48 | /**
49 | * Deserialize provided frame JSON text to [WebSocketFrame].
50 | */
51 | fun deserializeWebSocketMessage(text: String): WebSocketFrame {
52 | return Json.decodeFromString(WebSocketFrameSerializer, text)
53 | }
54 |
55 | /**
56 | * WebSocketFrameSerializer decodes raw WebSocket JSON message by inspecting [JsonElement] and trying to guess correct [WebSocketFrame] type.
57 | */
58 | internal object WebSocketFrameSerializer : JsonContentPolymorphicSerializer(WebSocketFrame::class) {
59 | override fun selectDeserializer(element: JsonElement) = when {
60 | "error" in element.jsonObject -> ErrorResponseFrame.serializer()
61 | "method" in element.jsonObject -> EventResponseFrame.serializer()
62 | "id" in element.jsonObject -> RequestResponseFrame.serializer()
63 | else -> throw RuntimeException("Unrecognized frame with JSON representation: $element")
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/console/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.console
2 |
3 | /**
4 | * This domain is deprecated - use Runtime or Log instead.
5 | *
6 | * @link Protocol [Console](https://chromedevtools.github.io/devtools-protocol/tot/Console) domain documentation.
7 | */
8 | @Deprecated(level = DeprecationLevel.WARNING, message = "This domain is deprecated - use Runtime or Log instead.")
9 | class ConsoleDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
10 | pl.wendigo.chrome.protocol.Domain("Console", """This domain is deprecated - use Runtime or Log instead.""", connection) {
11 | /**
12 | * Does nothing.
13 | *
14 | * @link Protocol [Console#clearMessages](https://chromedevtools.github.io/devtools-protocol/tot/Console#method-clearMessages) method documentation.
15 | */
16 |
17 | fun clearMessages(): io.reactivex.rxjava3.core.Single = connection.request("Console.clearMessages", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
18 |
19 | /**
20 | * Disables console domain, prevents further console messages from being reported to the client.
21 | *
22 | * @link Protocol [Console#disable](https://chromedevtools.github.io/devtools-protocol/tot/Console#method-disable) method documentation.
23 | */
24 |
25 | fun disable(): io.reactivex.rxjava3.core.Single = connection.request("Console.disable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
26 |
27 | /**
28 | * Enables console domain, sends the messages collected so far to the client by means of the
29 | `messageAdded` notification.
30 | *
31 | * @link Protocol [Console#enable](https://chromedevtools.github.io/devtools-protocol/tot/Console#method-enable) method documentation.
32 | */
33 |
34 | fun enable(): io.reactivex.rxjava3.core.Single = connection.request("Console.enable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
35 |
36 | /**
37 | * Issued when new console message is added.
38 | */
39 | fun messageAdded(): io.reactivex.rxjava3.core.Flowable = connection.events("Console.messageAdded", MessageAddedEvent.serializer())
40 |
41 | /**
42 | * Returns list of dependant domains that should be enabled prior to enabling this domain.
43 | */
44 | override fun getDependencies(): List {
45 | return arrayListOf(
46 | pl.wendigo.chrome.api.runtime.RuntimeDomain(connection),
47 | )
48 | }
49 | }
50 |
51 | /**
52 | * Issued when new console message is added.
53 | *
54 | * @link [Console#messageAdded](https://chromedevtools.github.io/devtools-protocol/tot/Console#event-messageAdded) event documentation.
55 | */
56 | @kotlinx.serialization.Serializable
57 | data class MessageAddedEvent(
58 | /**
59 | * Console message that has been added.
60 | */
61 | val message: ConsoleMessage
62 |
63 | ) : pl.wendigo.chrome.protocol.Event {
64 | override fun domain() = "Console"
65 | override fun eventName() = "messageAdded"
66 | }
67 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@serafin.tech. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/media/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.media
2 |
3 | /**
4 | * Players will get an ID that is unique within the agent context.
5 | *
6 | * @link [Media#PlayerId](https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerId) type documentation.
7 | */
8 |
9 | typealias PlayerId = String
10 |
11 | /**
12 | *
13 | *
14 | * @link [Media#Timestamp](https://chromedevtools.github.io/devtools-protocol/tot/Media#type-Timestamp) type documentation.
15 | */
16 |
17 | typealias Timestamp = Double
18 |
19 | /**
20 | * Have one type per entry in MediaLogRecord::Type
21 | Corresponds to kMessage
22 | *
23 | * @link [Media#PlayerMessage](https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerMessage) type documentation.
24 | */
25 |
26 | @kotlinx.serialization.Serializable
27 | data class PlayerMessage(
28 | /**
29 | * Keep in sync with MediaLogMessageLevel
30 | We are currently keeping the message level 'error' separate from the
31 | PlayerError type because right now they represent different things,
32 | this one being a DVLOG(ERROR) style log message that gets printed
33 | based on what log level is selected in the UI, and the other is a
34 | representation of a media::PipelineStatus object. Soon however we're
35 | going to be moving away from using PipelineStatus for errors and
36 | introducing a new error type which should hopefully let us integrate
37 | the error log level into the PlayerError type.
38 | */
39 | val level: String,
40 |
41 | /**
42 | *
43 | */
44 | val message: String
45 | )
46 |
47 | /**
48 | * Corresponds to kMediaPropertyChange
49 | *
50 | * @link [Media#PlayerProperty](https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerProperty) type documentation.
51 | */
52 |
53 | @kotlinx.serialization.Serializable
54 | data class PlayerProperty(
55 | /**
56 | *
57 | */
58 | val name: String,
59 |
60 | /**
61 | *
62 | */
63 | val value: String
64 | )
65 |
66 | /**
67 | * Corresponds to kMediaEventTriggered
68 | *
69 | * @link [Media#PlayerEvent](https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerEvent) type documentation.
70 | */
71 |
72 | @kotlinx.serialization.Serializable
73 | data class PlayerEvent(
74 | /**
75 | *
76 | */
77 | val timestamp: Timestamp,
78 |
79 | /**
80 | *
81 | */
82 | val value: String
83 | )
84 |
85 | /**
86 | * Corresponds to kMediaError
87 | *
88 | * @link [Media#PlayerError](https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerError) type documentation.
89 | */
90 |
91 | @kotlinx.serialization.Serializable
92 | data class PlayerError(
93 | /**
94 | *
95 | */
96 | val type: String,
97 |
98 | /**
99 | * When this switches to using media::Status instead of PipelineStatus
100 | we can remove "errorCode" and replace it with the fields from
101 | a Status instance. This also seems like a duplicate of the error
102 | level enum - there is a todo bug to have that level removed and
103 | use this instead. (crbug.com/1068454)
104 | */
105 | val errorCode: String
106 | )
107 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/tracing/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.tracing
2 |
3 | /**
4 | * Configuration for memory dump. Used only when "memory-infra" category is enabled.
5 | *
6 | * @link [Tracing#MemoryDumpConfig](https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-MemoryDumpConfig) type documentation.
7 | */
8 |
9 | typealias MemoryDumpConfig = Map
10 |
11 | /**
12 | *
13 | *
14 | * @link [Tracing#TraceConfig](https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-TraceConfig) type documentation.
15 | */
16 |
17 | @kotlinx.serialization.Serializable
18 | data class TraceConfig(
19 | /**
20 | * Controls how the trace buffer stores data.
21 | */
22 | val recordMode: String? = null,
23 |
24 | /**
25 | * Turns on JavaScript stack sampling.
26 | */
27 | val enableSampling: Boolean? = null,
28 |
29 | /**
30 | * Turns on system tracing.
31 | */
32 | val enableSystrace: Boolean? = null,
33 |
34 | /**
35 | * Turns on argument filter.
36 | */
37 | val enableArgumentFilter: Boolean? = null,
38 |
39 | /**
40 | * Included category filters.
41 | */
42 | val includedCategories: List? = null,
43 |
44 | /**
45 | * Excluded category filters.
46 | */
47 | val excludedCategories: List? = null,
48 |
49 | /**
50 | * Configuration to synthesize the delays in tracing.
51 | */
52 | val syntheticDelays: List? = null,
53 |
54 | /**
55 | * Configuration for memory dump triggers. Used only when "memory-infra" category is enabled.
56 | */
57 | val memoryDumpConfig: MemoryDumpConfig? = null
58 | )
59 |
60 | /**
61 | * Data format of a trace. Can be either the legacy JSON format or the
62 | protocol buffer format. Note that the JSON format will be deprecated soon.
63 | *
64 | * @link [Tracing#StreamFormat](https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-StreamFormat) type documentation.
65 | */
66 | @kotlinx.serialization.Serializable
67 | enum class StreamFormat {
68 | @kotlinx.serialization.SerialName("json")
69 | JSON,
70 |
71 | @kotlinx.serialization.SerialName("proto")
72 | PROTO;
73 | }
74 |
75 | /**
76 | * Compression type to use for traces returned via streams.
77 | *
78 | * @link [Tracing#StreamCompression](https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-StreamCompression) type documentation.
79 | */
80 | @kotlinx.serialization.Serializable
81 | enum class StreamCompression {
82 | @kotlinx.serialization.SerialName("none")
83 | NONE,
84 |
85 | @kotlinx.serialization.SerialName("gzip")
86 | GZIP;
87 | }
88 |
89 | /**
90 | * Details exposed when memory request explicitly declared.
91 | Keep consistent with memory_dump_request_args.h and
92 | memory_instrumentation.mojom
93 | *
94 | * @link [Tracing#MemoryDumpLevelOfDetail](https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-MemoryDumpLevelOfDetail) type documentation.
95 | */
96 | @kotlinx.serialization.Serializable
97 | enum class MemoryDumpLevelOfDetail {
98 | @kotlinx.serialization.SerialName("background")
99 | BACKGROUND,
100 |
101 | @kotlinx.serialization.SerialName("light")
102 | LIGHT,
103 |
104 | @kotlinx.serialization.SerialName("detailed")
105 | DETAILED;
106 | }
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # chrome-reactive-kotlin v0.7.1
2 |
3 | [](https://maven-badges.herokuapp.com/maven-central/pl.wendigo/chrome-reactive-kotlin) [](https://www.javadoc.io/doc/pl.wendigo/chrome-reactive-kotlin) [](https://github.com/wendigo/chrome-reactive-kotlin/actions/workflows/tests-with-gradle.yml) [](https://github.com/wendigo/chrome-reactive-kotlin/actions?workflow=Update+protocol+to+ToT) [](https://dependabot.com)
4 |
5 | **chrome-reactive-kotlin** is a low level [Chrome DevTools Protocol](https://chromedevtools.github.io/debugger-protocol-viewer/) client written in [Kotlin](https://kotlinlang.org) and leveraging [RxJava3](https://github.com/ReactiveX/RxJava) for easy composability.
6 |
7 | Library exposes all protocol domains in a single, cohesive and highly composable API. It supports both headless and standalone Chrome versions and supports creating isolated environments via [BrowserContext](https://chromedevtools.github.io/debugger-protocol-viewer/tot/Target/) from [Target]((https://chromedevtools.github.io/debugger-protocol-viewer/tot/Target/)) domain and flatted sessions mode (see: [http://crbug.com/991325](http://crbug.com/991325)).
8 |
9 | For debugging purposes you can use my other project: [chrome-protocol-proxy](https://github.com/wendigo/chrome-protocol-proxy).
10 |
11 | Please note that most up-to-date protocol is used at the moment.
12 |
13 | **Documentation can be found on [https://wendigo.github.io/chrome-reactive-kotlin/](https://wendigo.github.io/chrome-reactive-kotlin/).**
14 |
15 | # Usage
16 |
17 | ## Gradle
18 |
19 | `build.gradle`:
20 | ```groovy
21 | implementation 'pl.wendigo:chrome-reactive-kotlin:0.7.1'
22 | ```
23 |
24 | `build.gradle.kts`:
25 | ```kotlin
26 | implementation("pl.wendigo:chrome-reactive-kotlin:0.7.1")
27 | ```
28 |
29 | ## Maven
30 |
31 | `pom.xml`:
32 |
33 | ```xml
34 |
35 | pl.wendigo
36 | chrome-reactive-kotlin
37 | 0.7.1
38 |
39 | ```
40 |
41 | # Example
42 |
43 | Run headless chrome:
44 |
45 | ```
46 | docker container run -d -p 9222:9222 eu.gcr.io/zenika-hub/alpine-chrome:89 --no-sandbox --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222 about:blank
47 | ```
48 |
49 | And now execute:
50 |
51 | ```kotlin
52 | import pl.wendigo.chrome.api.page.NavigateRequest
53 |
54 | fun main() {
55 | val chrome = Browser.builder()
56 | .withAddress("127.0.0.1:9222")
57 | .build()
58 |
59 | chrome.use { browser ->
60 | browser.target("about:blank").use { target ->
61 | await {
62 | target.Page.enable()
63 | }
64 |
65 | await {
66 | target.Page.navigate(NavigateRequest(url = "https://github.com/wendigo/chrome-reactive-kotlin")).flatMap { (frameId) ->
67 | target.Page.frameStoppedLoading().filter {
68 | it.frameId == frameId
69 | }.take(1).singleOrError()
70 | }
71 | }
72 | }
73 | }
74 | }
75 | ```
76 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/systeminfo/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.systeminfo
2 |
3 | /**
4 | * The SystemInfo domain defines methods and events for querying low-level system information.
5 | *
6 | * This API is marked as experimental in protocol definition and can change in the future.
7 | * @link Protocol [SystemInfo](https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo) domain documentation.
8 | */
9 | @pl.wendigo.chrome.protocol.Experimental
10 | class SystemInfoDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
11 | pl.wendigo.chrome.protocol.Domain("SystemInfo", """The SystemInfo domain defines methods and events for querying low-level system information.""", connection) {
12 | /**
13 | * Returns information about the system.
14 | *
15 | * @link Protocol [SystemInfo#getInfo](https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getInfo) method documentation.
16 | */
17 |
18 | fun getInfo(): io.reactivex.rxjava3.core.Single = connection.request("SystemInfo.getInfo", null, GetInfoResponse.serializer())
19 |
20 | /**
21 | * Returns information about all running processes.
22 | *
23 | * @link Protocol [SystemInfo#getProcessInfo](https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getProcessInfo) method documentation.
24 | */
25 |
26 | fun getProcessInfo(): io.reactivex.rxjava3.core.Single = connection.request("SystemInfo.getProcessInfo", null, GetProcessInfoResponse.serializer())
27 | }
28 |
29 | /**
30 | * Represents response frame that is returned from [SystemInfo#getInfo](https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getInfo) operation call.
31 | * Returns information about the system.
32 | *
33 |
34 | * @link [SystemInfo#getInfo](https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getInfo) method documentation.
35 | * @see [SystemInfoDomain.getInfo]
36 | */
37 | @kotlinx.serialization.Serializable
38 | data class GetInfoResponse(
39 | /**
40 | * Information about the GPUs on the system.
41 | */
42 | val gpu: GPUInfo,
43 |
44 | /**
45 | * A platform-dependent description of the model of the machine. On Mac OS, this is, for
46 | example, 'MacBookPro'. Will be the empty string if not supported.
47 | */
48 | val modelName: String,
49 |
50 | /**
51 | * A platform-dependent description of the version of the machine. On Mac OS, this is, for
52 | example, '10.1'. Will be the empty string if not supported.
53 | */
54 | val modelVersion: String,
55 |
56 | /**
57 | * The command line string used to launch the browser. Will be the empty string if not
58 | supported.
59 | */
60 | val commandLine: String
61 |
62 | )
63 |
64 | /**
65 | * Represents response frame that is returned from [SystemInfo#getProcessInfo](https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getProcessInfo) operation call.
66 | * Returns information about all running processes.
67 | *
68 |
69 | * @link [SystemInfo#getProcessInfo](https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getProcessInfo) method documentation.
70 | * @see [SystemInfoDomain.getProcessInfo]
71 | */
72 | @kotlinx.serialization.Serializable
73 | data class GetProcessInfoResponse(
74 | /**
75 | * An array of process info blocks.
76 | */
77 | val processInfo: List
78 |
79 | )
80 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/cachestorage/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.cachestorage
2 |
3 | /**
4 | * Unique identifier of the Cache object.
5 | *
6 | * @link [CacheStorage#CacheId](https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-CacheId) type documentation.
7 | */
8 |
9 | typealias CacheId = String
10 |
11 | /**
12 | * type of HTTP response cached
13 | *
14 | * @link [CacheStorage#CachedResponseType](https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-CachedResponseType) type documentation.
15 | */
16 | @kotlinx.serialization.Serializable
17 | enum class CachedResponseType {
18 | @kotlinx.serialization.SerialName("basic")
19 | BASIC,
20 |
21 | @kotlinx.serialization.SerialName("cors")
22 | CORS,
23 |
24 | @kotlinx.serialization.SerialName("default")
25 | DEFAULT,
26 |
27 | @kotlinx.serialization.SerialName("error")
28 | ERROR,
29 |
30 | @kotlinx.serialization.SerialName("opaqueResponse")
31 | OPAQUERESPONSE,
32 |
33 | @kotlinx.serialization.SerialName("opaqueRedirect")
34 | OPAQUEREDIRECT;
35 | }
36 |
37 | /**
38 | * Data entry.
39 | *
40 | * @link [CacheStorage#DataEntry](https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-DataEntry) type documentation.
41 | */
42 |
43 | @kotlinx.serialization.Serializable
44 | data class DataEntry(
45 | /**
46 | * Request URL.
47 | */
48 | val requestURL: String,
49 |
50 | /**
51 | * Request method.
52 | */
53 | val requestMethod: String,
54 |
55 | /**
56 | * Request headers
57 | */
58 | val requestHeaders: List,
59 |
60 | /**
61 | * Number of seconds since epoch.
62 | */
63 | val responseTime: Double,
64 |
65 | /**
66 | * HTTP response status code.
67 | */
68 | val responseStatus: Int,
69 |
70 | /**
71 | * HTTP response status text.
72 | */
73 | val responseStatusText: String,
74 |
75 | /**
76 | * HTTP response type
77 | */
78 | val responseType: CachedResponseType,
79 |
80 | /**
81 | * Response headers
82 | */
83 | val responseHeaders: List
84 | )
85 |
86 | /**
87 | * Cache identifier.
88 | *
89 | * @link [CacheStorage#Cache](https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-Cache) type documentation.
90 | */
91 |
92 | @kotlinx.serialization.Serializable
93 | data class Cache(
94 | /**
95 | * An opaque unique id of the cache.
96 | */
97 | val cacheId: CacheId,
98 |
99 | /**
100 | * Security origin of the cache.
101 | */
102 | val securityOrigin: String,
103 |
104 | /**
105 | * The name of the cache.
106 | */
107 | val cacheName: String
108 | )
109 |
110 | /**
111 | *
112 | *
113 | * @link [CacheStorage#Header](https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-Header) type documentation.
114 | */
115 |
116 | @kotlinx.serialization.Serializable
117 | data class Header(
118 | /**
119 | *
120 | */
121 | val name: String,
122 |
123 | /**
124 | *
125 | */
126 | val value: String
127 | )
128 |
129 | /**
130 | * Cached response
131 | *
132 | * @link [CacheStorage#CachedResponse](https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-CachedResponse) type documentation.
133 | */
134 |
135 | @kotlinx.serialization.Serializable
136 | data class CachedResponse(
137 | /**
138 | * Entry content, base64-encoded. (Encoded as a base64 string when passed over JSON)
139 | */
140 | val body: String
141 | )
142 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/tethering/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.tethering
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * The Tethering domain defines methods and events for browser port binding.
7 | *
8 | * This API is marked as experimental in protocol definition and can change in the future.
9 | * @link Protocol [Tethering](https://chromedevtools.github.io/devtools-protocol/tot/Tethering) domain documentation.
10 | */
11 | @pl.wendigo.chrome.protocol.Experimental
12 | class TetheringDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
13 | pl.wendigo.chrome.protocol.Domain("Tethering", """The Tethering domain defines methods and events for browser port binding.""", connection) {
14 | /**
15 | * Request browser port binding.
16 | *
17 | * @link Protocol [Tethering#bind](https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-bind) method documentation.
18 | */
19 |
20 | fun bind(input: BindRequest): io.reactivex.rxjava3.core.Single = connection.request("Tethering.bind", Json.encodeToJsonElement(BindRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
21 |
22 | /**
23 | * Request browser port unbinding.
24 | *
25 | * @link Protocol [Tethering#unbind](https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-unbind) method documentation.
26 | */
27 |
28 | fun unbind(input: UnbindRequest): io.reactivex.rxjava3.core.Single = connection.request("Tethering.unbind", Json.encodeToJsonElement(UnbindRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
29 |
30 | /**
31 | * Informs that port was successfully bound and got a specified connection id.
32 | */
33 | fun accepted(): io.reactivex.rxjava3.core.Flowable = connection.events("Tethering.accepted", AcceptedEvent.serializer())
34 | }
35 |
36 | /**
37 | * Represents request frame that can be used with [Tethering#bind](https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-bind) operation call.
38 | *
39 | * Request browser port binding.
40 | * @link [Tethering#bind](https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-bind) method documentation.
41 | * @see [TetheringDomain.bind]
42 | */
43 | @kotlinx.serialization.Serializable
44 | data class BindRequest(
45 | /**
46 | * Port number to bind.
47 | */
48 | val port: Int
49 |
50 | )
51 |
52 | /**
53 | * Represents request frame that can be used with [Tethering#unbind](https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-unbind) operation call.
54 | *
55 | * Request browser port unbinding.
56 | * @link [Tethering#unbind](https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-unbind) method documentation.
57 | * @see [TetheringDomain.unbind]
58 | */
59 | @kotlinx.serialization.Serializable
60 | data class UnbindRequest(
61 | /**
62 | * Port number to unbind.
63 | */
64 | val port: Int
65 |
66 | )
67 |
68 | /**
69 | * Informs that port was successfully bound and got a specified connection id.
70 | *
71 | * @link [Tethering#accepted](https://chromedevtools.github.io/devtools-protocol/tot/Tethering#event-accepted) event documentation.
72 | */
73 | @kotlinx.serialization.Serializable
74 | data class AcceptedEvent(
75 | /**
76 | * Port number that was successfully bound.
77 | */
78 | val port: Int,
79 |
80 | /**
81 | * Connection id to be used.
82 | */
83 | val connectionId: String
84 |
85 | ) : pl.wendigo.chrome.protocol.Event {
86 | override fun domain() = "Tethering"
87 | override fun eventName() = "accepted"
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/performancetimeline/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.performancetimeline
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * Reporting of performance timeline events, as specified in
7 | https://w3c.github.io/performance-timeline/#dom-performanceobserver.
8 | *
9 | * This API is marked as experimental in protocol definition and can change in the future.
10 | * @link Protocol [PerformanceTimeline](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline) domain documentation.
11 | */
12 | @pl.wendigo.chrome.protocol.Experimental
13 | class PerformanceTimelineDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
14 | pl.wendigo.chrome.protocol.Domain(
15 | "PerformanceTimeline",
16 | """Reporting of performance timeline events, as specified in
17 | https://w3c.github.io/performance-timeline/#dom-performanceobserver.""",
18 | connection
19 | ) {
20 | /**
21 | * Previously buffered events would be reported before method returns.
22 | See also: timelineEventAdded
23 | *
24 | * @link Protocol [PerformanceTimeline#enable](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#method-enable) method documentation.
25 | */
26 |
27 | fun enable(input: EnableRequest): io.reactivex.rxjava3.core.Single = connection.request("PerformanceTimeline.enable", Json.encodeToJsonElement(EnableRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
28 |
29 | /**
30 | * Sent when a performance timeline event is added. See reportPerformanceTimeline method.
31 | */
32 | fun timelineEventAdded(): io.reactivex.rxjava3.core.Flowable = connection.events("PerformanceTimeline.timelineEventAdded", TimelineEventAddedEvent.serializer())
33 |
34 | /**
35 | * Returns list of dependant domains that should be enabled prior to enabling this domain.
36 | */
37 | override fun getDependencies(): List {
38 | return arrayListOf(
39 | pl.wendigo.chrome.api.dom.DOMDomain(connection),
40 | pl.wendigo.chrome.api.network.NetworkDomain(connection),
41 | )
42 | }
43 | }
44 |
45 | /**
46 | * Represents request frame that can be used with [PerformanceTimeline#enable](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#method-enable) operation call.
47 | *
48 | * Previously buffered events would be reported before method returns.
49 | See also: timelineEventAdded
50 | * @link [PerformanceTimeline#enable](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#method-enable) method documentation.
51 | * @see [PerformanceTimelineDomain.enable]
52 | */
53 | @kotlinx.serialization.Serializable
54 | data class EnableRequest(
55 | /**
56 | * The types of event to report, as specified in
57 | https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype
58 | The specified filter overrides any previous filters, passing empty
59 | filter disables recording.
60 | Note that not all types exposed to the web platform are currently supported.
61 | */
62 | val eventTypes: List
63 |
64 | )
65 |
66 | /**
67 | * Sent when a performance timeline event is added. See reportPerformanceTimeline method.
68 | *
69 | * @link [PerformanceTimeline#timelineEventAdded](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#event-timelineEventAdded) event documentation.
70 | */
71 | @kotlinx.serialization.Serializable
72 | data class TimelineEventAddedEvent(
73 | /**
74 | *
75 | */
76 | val event: TimelineEvent
77 |
78 | ) : pl.wendigo.chrome.protocol.Event {
79 | override fun domain() = "PerformanceTimeline"
80 | override fun eventName() = "timelineEventAdded"
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/input/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.input
2 |
3 | /**
4 | *
5 | *
6 | * @link [Input#TouchPoint](https://chromedevtools.github.io/devtools-protocol/tot/Input#type-TouchPoint) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class TouchPoint(
11 | /**
12 | * X coordinate of the event relative to the main frame's viewport in CSS pixels.
13 | */
14 | val x: Double,
15 |
16 | /**
17 | * Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to
18 | the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.
19 | */
20 | val y: Double,
21 |
22 | /**
23 | * X radius of the touch area (default: 1.0).
24 | */
25 | val radiusX: Double? = null,
26 |
27 | /**
28 | * Y radius of the touch area (default: 1.0).
29 | */
30 | val radiusY: Double? = null,
31 |
32 | /**
33 | * Rotation angle (default: 0.0).
34 | */
35 | val rotationAngle: Double? = null,
36 |
37 | /**
38 | * Force (default: 1.0).
39 | */
40 | val force: Double? = null,
41 |
42 | /**
43 | * The normalized tangential pressure, which has a range of [-1,1] (default: 0).
44 | */
45 | @pl.wendigo.chrome.protocol.Experimental val tangentialPressure: Double? = null,
46 |
47 | /**
48 | * The plane angle between the Y-Z plane and the plane containing both the stylus axis and the Y axis, in degrees of the range [-90,90], a positive tiltX is to the right (default: 0)
49 | */
50 | @pl.wendigo.chrome.protocol.Experimental val tiltX: Int? = null,
51 |
52 | /**
53 | * The plane angle between the X-Z plane and the plane containing both the stylus axis and the X axis, in degrees of the range [-90,90], a positive tiltY is towards the user (default: 0).
54 | */
55 | @pl.wendigo.chrome.protocol.Experimental val tiltY: Int? = null,
56 |
57 | /**
58 | * The clockwise rotation of a pen stylus around its own major axis, in degrees in the range [0,359] (default: 0).
59 | */
60 | @pl.wendigo.chrome.protocol.Experimental val twist: Int? = null,
61 |
62 | /**
63 | * Identifier used to track touch sources between events, must be unique within an event.
64 | */
65 | val id: Double? = null
66 | )
67 |
68 | /**
69 | *
70 | *
71 | * @link [Input#GestureSourceType](https://chromedevtools.github.io/devtools-protocol/tot/Input#type-GestureSourceType) type documentation.
72 | */
73 | @kotlinx.serialization.Serializable
74 | enum class GestureSourceType {
75 | @kotlinx.serialization.SerialName("default")
76 | DEFAULT,
77 |
78 | @kotlinx.serialization.SerialName("touch")
79 | TOUCH,
80 |
81 | @kotlinx.serialization.SerialName("mouse")
82 | MOUSE;
83 | }
84 |
85 | /**
86 | *
87 | *
88 | * @link [Input#MouseButton](https://chromedevtools.github.io/devtools-protocol/tot/Input#type-MouseButton) type documentation.
89 | */
90 | @kotlinx.serialization.Serializable
91 | enum class MouseButton {
92 | @kotlinx.serialization.SerialName("none")
93 | NONE,
94 |
95 | @kotlinx.serialization.SerialName("left")
96 | LEFT,
97 |
98 | @kotlinx.serialization.SerialName("middle")
99 | MIDDLE,
100 |
101 | @kotlinx.serialization.SerialName("right")
102 | RIGHT,
103 |
104 | @kotlinx.serialization.SerialName("back")
105 | BACK,
106 |
107 | @kotlinx.serialization.SerialName("forward")
108 | FORWARD;
109 | }
110 |
111 | /**
112 | * UTC time in seconds, counted from January 1, 1970.
113 | *
114 | * @link [Input#TimeSinceEpoch](https://chromedevtools.github.io/devtools-protocol/tot/Input#type-TimeSinceEpoch) type documentation.
115 | */
116 |
117 | typealias TimeSinceEpoch = Double
118 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/fetch/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.fetch
2 |
3 | /**
4 | * Unique request identifier.
5 | *
6 | * @link [Fetch#RequestId](https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-RequestId) type documentation.
7 | */
8 |
9 | typealias RequestId = String
10 |
11 | /**
12 | * Stages of the request to handle. Request will intercept before the request is
13 | sent. Response will intercept after the response is received (but before response
14 | body is received.
15 | *
16 | * @link [Fetch#RequestStage](https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-RequestStage) type documentation.
17 | */
18 | @kotlinx.serialization.Serializable
19 | enum class RequestStage {
20 | @kotlinx.serialization.SerialName("Request")
21 | REQUEST,
22 |
23 | @kotlinx.serialization.SerialName("Response")
24 | RESPONSE;
25 | }
26 |
27 | /**
28 | *
29 | *
30 | * @link [Fetch#RequestPattern](https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-RequestPattern) type documentation.
31 | */
32 |
33 | @kotlinx.serialization.Serializable
34 | data class RequestPattern(
35 | /**
36 | * Wildcards ('*' -> zero or more, '?' -> exactly one) are allowed. Escape character is
37 | backslash. Omitting is equivalent to "*".
38 | */
39 | val urlPattern: String? = null,
40 |
41 | /**
42 | * If set, only requests for matching resource types will be intercepted.
43 | */
44 | val resourceType: pl.wendigo.chrome.api.network.ResourceType? = null,
45 |
46 | /**
47 | * Stage at wich to begin intercepting requests. Default is Request.
48 | */
49 | val requestStage: RequestStage? = null
50 | )
51 |
52 | /**
53 | * Response HTTP header entry
54 | *
55 | * @link [Fetch#HeaderEntry](https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-HeaderEntry) type documentation.
56 | */
57 |
58 | @kotlinx.serialization.Serializable
59 | data class HeaderEntry(
60 | /**
61 | *
62 | */
63 | val name: String,
64 |
65 | /**
66 | *
67 | */
68 | val value: String
69 | )
70 |
71 | /**
72 | * Authorization challenge for HTTP status code 401 or 407.
73 | *
74 | * @link [Fetch#AuthChallenge](https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-AuthChallenge) type documentation.
75 | */
76 |
77 | @kotlinx.serialization.Serializable
78 | data class AuthChallenge(
79 | /**
80 | * Source of the authentication challenge.
81 | */
82 | val source: String? = null,
83 |
84 | /**
85 | * Origin of the challenger.
86 | */
87 | val origin: String,
88 |
89 | /**
90 | * The authentication scheme used, such as basic or digest
91 | */
92 | val scheme: String,
93 |
94 | /**
95 | * The realm of the challenge. May be empty.
96 | */
97 | val realm: String
98 | )
99 |
100 | /**
101 | * Response to an AuthChallenge.
102 | *
103 | * @link [Fetch#AuthChallengeResponse](https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-AuthChallengeResponse) type documentation.
104 | */
105 |
106 | @kotlinx.serialization.Serializable
107 | data class AuthChallengeResponse(
108 | /**
109 | * The decision on what to do in response to the authorization challenge. Default means
110 | deferring to the default behavior of the net stack, which will likely either the Cancel
111 | authentication or display a popup dialog box.
112 | */
113 | val response: String,
114 |
115 | /**
116 | * The username to provide, possibly empty. Should only be set if response is
117 | ProvideCredentials.
118 | */
119 | val username: String? = null,
120 |
121 | /**
122 | * The password to provide, possibly empty. Should only be set if response is
123 | ProvideCredentials.
124 | */
125 | val password: String? = null
126 | )
127 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/performancetimeline/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.performancetimeline
2 |
3 | /**
4 | * See https://github.com/WICG/LargestContentfulPaint and largest_contentful_paint.idl
5 | *
6 | * @link [PerformanceTimeline#LargestContentfulPaint](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-LargestContentfulPaint) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class LargestContentfulPaint(
11 | /**
12 | *
13 | */
14 | val renderTime: pl.wendigo.chrome.api.network.TimeSinceEpoch,
15 |
16 | /**
17 | *
18 | */
19 | val loadTime: pl.wendigo.chrome.api.network.TimeSinceEpoch,
20 |
21 | /**
22 | * The number of pixels being painted.
23 | */
24 | val size: Double,
25 |
26 | /**
27 | * The id attribute of the element, if available.
28 | */
29 | val elementId: String? = null,
30 |
31 | /**
32 | * The URL of the image (may be trimmed).
33 | */
34 | val url: String? = null,
35 |
36 | /**
37 | *
38 | */
39 | val nodeId: pl.wendigo.chrome.api.dom.BackendNodeId? = null
40 | )
41 |
42 | /**
43 | *
44 | *
45 | * @link [PerformanceTimeline#LayoutShiftAttribution](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-LayoutShiftAttribution) type documentation.
46 | */
47 |
48 | @kotlinx.serialization.Serializable
49 | data class LayoutShiftAttribution(
50 | /**
51 | *
52 | */
53 | val previousRect: pl.wendigo.chrome.api.dom.Rect,
54 |
55 | /**
56 | *
57 | */
58 | val currentRect: pl.wendigo.chrome.api.dom.Rect,
59 |
60 | /**
61 | *
62 | */
63 | val nodeId: pl.wendigo.chrome.api.dom.BackendNodeId? = null
64 | )
65 |
66 | /**
67 | * See https://wicg.github.io/layout-instability/#sec-layout-shift and layout_shift.idl
68 | *
69 | * @link [PerformanceTimeline#LayoutShift](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-LayoutShift) type documentation.
70 | */
71 |
72 | @kotlinx.serialization.Serializable
73 | data class LayoutShift(
74 | /**
75 | * Score increment produced by this event.
76 | */
77 | val value: Double,
78 |
79 | /**
80 | *
81 | */
82 | val hadRecentInput: Boolean,
83 |
84 | /**
85 | *
86 | */
87 | val lastInputTime: pl.wendigo.chrome.api.network.TimeSinceEpoch,
88 |
89 | /**
90 | *
91 | */
92 | val sources: List
93 | )
94 |
95 | /**
96 | *
97 | *
98 | * @link [PerformanceTimeline#TimelineEvent](https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-TimelineEvent) type documentation.
99 | */
100 |
101 | @kotlinx.serialization.Serializable
102 | data class TimelineEvent(
103 | /**
104 | * Identifies the frame that this event is related to. Empty for non-frame targets.
105 | */
106 | val frameId: pl.wendigo.chrome.api.page.FrameId,
107 |
108 | /**
109 | * The event type, as specified in https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype
110 | This determines which of the optional "details" fiedls is present.
111 | */
112 | val type: String,
113 |
114 | /**
115 | * Name may be empty depending on the type.
116 | */
117 | val name: String,
118 |
119 | /**
120 | * Time in seconds since Epoch, monotonically increasing within document lifetime.
121 | */
122 | val time: pl.wendigo.chrome.api.network.TimeSinceEpoch,
123 |
124 | /**
125 | * Event duration, if applicable.
126 | */
127 | val duration: Double? = null,
128 |
129 | /**
130 | *
131 | */
132 | val lcpDetails: LargestContentfulPaint? = null,
133 |
134 | /**
135 | *
136 | */
137 | val layoutShiftDetails: LayoutShift? = null
138 | )
139 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/animation/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.animation
2 |
3 | /**
4 | * Animation instance.
5 | *
6 | * @link [Animation#Animation](https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-Animation) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class Animation(
11 | /**
12 | * `Animation`'s id.
13 | */
14 | val id: String,
15 |
16 | /**
17 | * `Animation`'s name.
18 | */
19 | val name: String,
20 |
21 | /**
22 | * `Animation`'s internal paused state.
23 | */
24 | val pausedState: Boolean,
25 |
26 | /**
27 | * `Animation`'s play state.
28 | */
29 | val playState: String,
30 |
31 | /**
32 | * `Animation`'s playback rate.
33 | */
34 | val playbackRate: Double,
35 |
36 | /**
37 | * `Animation`'s start time.
38 | */
39 | val startTime: Double,
40 |
41 | /**
42 | * `Animation`'s current time.
43 | */
44 | val currentTime: Double,
45 |
46 | /**
47 | * Animation type of `Animation`.
48 | */
49 | val type: String,
50 |
51 | /**
52 | * `Animation`'s source animation node.
53 | */
54 | val source: AnimationEffect? = null,
55 |
56 | /**
57 | * A unique ID for `Animation` representing the sources that triggered this CSS
58 | animation/transition.
59 | */
60 | val cssId: String? = null
61 | )
62 |
63 | /**
64 | * AnimationEffect instance
65 | *
66 | * @link [Animation#AnimationEffect](https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-AnimationEffect) type documentation.
67 | */
68 |
69 | @kotlinx.serialization.Serializable
70 | data class AnimationEffect(
71 | /**
72 | * `AnimationEffect`'s delay.
73 | */
74 | val delay: Double,
75 |
76 | /**
77 | * `AnimationEffect`'s end delay.
78 | */
79 | val endDelay: Double,
80 |
81 | /**
82 | * `AnimationEffect`'s iteration start.
83 | */
84 | val iterationStart: Double,
85 |
86 | /**
87 | * `AnimationEffect`'s iterations.
88 | */
89 | val iterations: Double,
90 |
91 | /**
92 | * `AnimationEffect`'s iteration duration.
93 | */
94 | val duration: Double,
95 |
96 | /**
97 | * `AnimationEffect`'s playback direction.
98 | */
99 | val direction: String,
100 |
101 | /**
102 | * `AnimationEffect`'s fill mode.
103 | */
104 | val fill: String,
105 |
106 | /**
107 | * `AnimationEffect`'s target node.
108 | */
109 | val backendNodeId: pl.wendigo.chrome.api.dom.BackendNodeId? = null,
110 |
111 | /**
112 | * `AnimationEffect`'s keyframes.
113 | */
114 | val keyframesRule: KeyframesRule? = null,
115 |
116 | /**
117 | * `AnimationEffect`'s timing function.
118 | */
119 | val easing: String
120 | )
121 |
122 | /**
123 | * Keyframes Rule
124 | *
125 | * @link [Animation#KeyframesRule](https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-KeyframesRule) type documentation.
126 | */
127 |
128 | @kotlinx.serialization.Serializable
129 | data class KeyframesRule(
130 | /**
131 | * CSS keyframed animation's name.
132 | */
133 | val name: String? = null,
134 |
135 | /**
136 | * List of animation keyframes.
137 | */
138 | val keyframes: List
139 | )
140 |
141 | /**
142 | * Keyframe Style
143 | *
144 | * @link [Animation#KeyframeStyle](https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-KeyframeStyle) type documentation.
145 | */
146 |
147 | @kotlinx.serialization.Serializable
148 | data class KeyframeStyle(
149 | /**
150 | * Keyframe's time offset.
151 | */
152 | val offset: String,
153 |
154 | /**
155 | * `AnimationEffect`'s timing function.
156 | */
157 | val easing: String
158 | )
159 |
--------------------------------------------------------------------------------
/src/test/groovy/pl/wendigo/chrome/ChromeProtocolSpecification.groovy:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome
2 |
3 | import org.testcontainers.utility.DockerImageName
4 | import pl.wendigo.chrome.api.target.TargetCreatedEvent
5 | import pl.wendigo.chrome.protocol.Event
6 | import spock.lang.Specification
7 |
8 | class ChromeProtocolSpecification
9 | extends Specification
10 | {
11 | static def browser = Browser.builder()
12 | .runInDocker(true)
13 | .withDockerImage("eu.gcr.io/zenika-hub/alpine-chrome:89")
14 | .withEventsBufferSize(128)
15 | .withViewportHeight(600)
16 | .withViewportWidth(900)
17 | .incognito(true)
18 | .multiplexConnections(true)
19 | .build()
20 |
21 | def "should return browser information"()
22 | {
23 | expect:
24 | browser.browserInfo().browser == "HeadlessChrome/89.0.4389.72"
25 | browser.browserInfo().protocolVersion == "1.3"
26 | }
27 |
28 | def "should match protocol version"()
29 | {
30 | expect:
31 | browser.browserInfo().protocolVersion == browser.protocolVersion()
32 | }
33 |
34 | def "should capture target events"()
35 | {
36 | given:
37 | def targetCreated = [] as List
38 | browser.getTarget().targetCreated().subscribe(targetCreated.&add)
39 |
40 | when:
41 | def target = browser.target()
42 |
43 | then:
44 | targetCreated.findIndexOf {it.targetInfo.targetId == target.info().targetId} > -1
45 | browser.targets().findIndexOf {it.targetId == target.info().targetId} > -1
46 |
47 | cleanup:
48 | target.close()
49 | }
50 |
51 | def "should open new target given provided options"()
52 | {
53 | given:
54 | def target = browser.target()
55 |
56 | when:
57 | def layout = target.page.getLayoutMetrics().blockingGet()
58 |
59 | then:
60 | with(target) {
61 | session.sessionId != ""
62 | session.browserContextID != ""
63 | session.targetId != ""
64 | info().type == "page"
65 | }
66 |
67 | with(layout.layoutViewport) {
68 | clientHeight == 600
69 | clientWidth == 900
70 | }
71 |
72 | cleanup:
73 | target.close()
74 | }
75 |
76 | def "should open and navigate to new target"()
77 | {
78 | given:
79 | def target = browser.target("https://google.com")
80 | def events = [] as List
81 |
82 | when:
83 | target.getPage().events().subscribe(events.&add)
84 | target.getPage().enable()
85 |
86 | def frame = target.getPage().frameNavigated().blockingFirst()
87 |
88 | then:
89 | frame.frame.url == "https://www.google.com/"
90 | events.size() > 0
91 |
92 | cleanup:
93 | target.close()
94 | }
95 |
96 | def "should allow creating multiple browser instances"()
97 | {
98 | given:
99 | def container = new HeadlessChromeContainer(DockerImageName.parse("eu.gcr.io/zenika-hub/alpine-chrome:89"))
100 | container.start()
101 | when:
102 | def browser1 = Browser.builder().withAddress(container.getBrowserEndpoint()).build()
103 | def target1 = browser.target("https://google.com")
104 | target1.close()
105 | browser1.close()
106 |
107 | then:
108 | // this shouldn't fail
109 | def browser2 = Browser.builder().withAddress(container.getBrowserEndpoint()).build()
110 | def target2 = browser.target("https://google.com")
111 | target2.close()
112 | browser2.close()
113 |
114 | cleanup:
115 | container.stop()
116 | }
117 |
118 | def "should return project info"()
119 | {
120 | given:
121 | def version = Browser.buildInfo()
122 |
123 | expect:
124 | version.toString() =~ "^pl\\.wendigo:chrome-reactive-kotlin:(.*?) built from (.*?), rev (.*?)\$"
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/ProtocolConnection.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol
2 |
3 | import io.reactivex.rxjava3.core.Flowable
4 | import io.reactivex.rxjava3.core.Single
5 | import io.reactivex.rxjava3.schedulers.Schedulers
6 | import kotlinx.serialization.KSerializer
7 | import kotlinx.serialization.json.JsonElement
8 | import okhttp3.OkHttpClient
9 | import pl.wendigo.chrome.api.target.SessionID
10 | import pl.wendigo.chrome.protocol.websocket.FrameMapper
11 | import pl.wendigo.chrome.protocol.websocket.RequestFrame
12 | import pl.wendigo.chrome.protocol.websocket.WebSocketFramesStream
13 | import java.io.Closeable
14 | import java.util.concurrent.atomic.AtomicLong
15 |
16 | /**
17 | * ProtocolConnection represents connection to chrome's debugger via [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/).
18 | *
19 | * It depends on [WebSocketFramesStream] which is responsible for providing stream of WebSocket frames (both events and responses) and allows for sending request frames.
20 | *
21 | * [EventMapper] is responsible for mapping [pl.wendigo.chrome.protocol.websocket.EventResponseFrame]s to concrete [Event] representations.
22 | *
23 | * @see WebSocketFramesStream
24 | * @see FrameMapper
25 | * @see EventMapper
26 | */
27 | class ProtocolConnection constructor(
28 | private val frames: WebSocketFramesStream,
29 | private val eventMapper: EventMapper = ProtocolConnection.eventMapper,
30 | private val sessionId: SessionID? = null
31 | ) : Closeable, AutoCloseable {
32 | private val nextRequestId = AtomicLong(0)
33 |
34 | /**
35 | * Closes connection to remote debugger.
36 | */
37 | override fun close() {
38 | frames.close()
39 | }
40 |
41 | /**
42 | * Sends request and captures response from the stream.
43 | */
44 | fun request(methodName: String, request: JsonElement?, responseSerializer: KSerializer): Single {
45 | val requestFrame = RequestFrame(
46 | id = nextRequestId.incrementAndGet(),
47 | method = methodName,
48 | params = request,
49 | sessionId = sessionId
50 | )
51 |
52 | return frames.send(requestFrame).flatMap { sent ->
53 | if (sent) {
54 | frames.getResponse(requestFrame, responseSerializer)
55 | } else {
56 | Single.error(RequestFailed(requestFrame, "Could not enqueue message $request"))
57 | }
58 | }
59 | }
60 |
61 | /**
62 | * Captures events by given name and casts received messages to specified class.
63 | */
64 | fun events(eventName: String, serializer: KSerializer): Flowable where T : Event {
65 | return frames.eventFrames()
66 | .filter { frame -> frame.matches(eventName, sessionId) }
67 | .map { frame -> eventMapper.deserialize(frame, serializer) }
68 | .subscribeOn(Schedulers.io())
69 | }
70 |
71 | /**
72 | * Captures all events as generated by remote debugger
73 | */
74 | fun events(): Flowable {
75 | return frames.eventFrames()
76 | .filter { frame -> frame.matches(sessionId) }
77 | .map { frame -> eventMapper.deserialize(frame) }
78 | .subscribeOn(Schedulers.io())
79 | }
80 |
81 | /**
82 | * Reuse existing debugger connection but for new sessionID sharing underlying WebSocket connection.
83 | */
84 | internal fun cloneForSessionId(sessionID: SessionID): ProtocolConnection = ProtocolConnection(
85 | frames,
86 | eventMapper,
87 | sessionID
88 | )
89 |
90 | /**
91 | * Factory is responsible for opening debugger WebSocket connections to a given debugger uri.
92 | */
93 | companion object Factory {
94 | /**
95 | * Creates new ChromeDebuggerConnection session for given WebSocket uri and frames buffer size.
96 | */
97 | @JvmStatic
98 | fun open(webSocketUri: String, framesBufferSize: Int = 128): ProtocolConnection {
99 | return ProtocolConnection(
100 | WebSocketFramesStream(webSocketUri, framesBufferSize, frameMapper, OkHttpClient()),
101 | eventMapper
102 | )
103 | }
104 |
105 | private val frameMapper by lazy {
106 | FrameMapper()
107 | }
108 |
109 | private val eventMapper by lazy {
110 | EventMapper()
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/serviceworker/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.serviceworker
2 |
3 | /**
4 | *
5 | *
6 | * @link [ServiceWorker#RegistrationID](https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-RegistrationID) type documentation.
7 | */
8 |
9 | typealias RegistrationID = String
10 |
11 | /**
12 | * ServiceWorker registration.
13 | *
14 | * @link [ServiceWorker#ServiceWorkerRegistration](https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerRegistration) type documentation.
15 | */
16 |
17 | @kotlinx.serialization.Serializable
18 | data class ServiceWorkerRegistration(
19 | /**
20 | *
21 | */
22 | val registrationId: RegistrationID,
23 |
24 | /**
25 | *
26 | */
27 | val scopeURL: String,
28 |
29 | /**
30 | *
31 | */
32 | val isDeleted: Boolean
33 | )
34 |
35 | /**
36 | *
37 | *
38 | * @link [ServiceWorker#ServiceWorkerVersionRunningStatus](https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerVersionRunningStatus) type documentation.
39 | */
40 | @kotlinx.serialization.Serializable
41 | enum class ServiceWorkerVersionRunningStatus {
42 | @kotlinx.serialization.SerialName("stopped")
43 | STOPPED,
44 |
45 | @kotlinx.serialization.SerialName("starting")
46 | STARTING,
47 |
48 | @kotlinx.serialization.SerialName("running")
49 | RUNNING,
50 |
51 | @kotlinx.serialization.SerialName("stopping")
52 | STOPPING;
53 | }
54 |
55 | /**
56 | *
57 | *
58 | * @link [ServiceWorker#ServiceWorkerVersionStatus](https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerVersionStatus) type documentation.
59 | */
60 | @kotlinx.serialization.Serializable
61 | enum class ServiceWorkerVersionStatus {
62 | @kotlinx.serialization.SerialName("new")
63 | NEW,
64 |
65 | @kotlinx.serialization.SerialName("installing")
66 | INSTALLING,
67 |
68 | @kotlinx.serialization.SerialName("installed")
69 | INSTALLED,
70 |
71 | @kotlinx.serialization.SerialName("activating")
72 | ACTIVATING,
73 |
74 | @kotlinx.serialization.SerialName("activated")
75 | ACTIVATED,
76 |
77 | @kotlinx.serialization.SerialName("redundant")
78 | REDUNDANT;
79 | }
80 |
81 | /**
82 | * ServiceWorker version.
83 | *
84 | * @link [ServiceWorker#ServiceWorkerVersion](https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerVersion) type documentation.
85 | */
86 |
87 | @kotlinx.serialization.Serializable
88 | data class ServiceWorkerVersion(
89 | /**
90 | *
91 | */
92 | val versionId: String,
93 |
94 | /**
95 | *
96 | */
97 | val registrationId: RegistrationID,
98 |
99 | /**
100 | *
101 | */
102 | val scriptURL: String,
103 |
104 | /**
105 | *
106 | */
107 | val runningStatus: ServiceWorkerVersionRunningStatus,
108 |
109 | /**
110 | *
111 | */
112 | val status: ServiceWorkerVersionStatus,
113 |
114 | /**
115 | * The Last-Modified header value of the main script.
116 | */
117 | val scriptLastModified: Double? = null,
118 |
119 | /**
120 | * The time at which the response headers of the main script were received from the server.
121 | For cached script it is the last time the cache entry was validated.
122 | */
123 | val scriptResponseTime: Double? = null,
124 |
125 | /**
126 | *
127 | */
128 | val controlledClients: List? = null,
129 |
130 | /**
131 | *
132 | */
133 | val targetId: pl.wendigo.chrome.api.target.TargetID? = null
134 | )
135 |
136 | /**
137 | * ServiceWorker error message.
138 | *
139 | * @link [ServiceWorker#ServiceWorkerErrorMessage](https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerErrorMessage) type documentation.
140 | */
141 |
142 | @kotlinx.serialization.Serializable
143 | data class ServiceWorkerErrorMessage(
144 | /**
145 | *
146 | */
147 | val errorMessage: String,
148 |
149 | /**
150 | *
151 | */
152 | val registrationId: RegistrationID,
153 |
154 | /**
155 | *
156 | */
157 | val versionId: String,
158 |
159 | /**
160 | *
161 | */
162 | val sourceURL: String,
163 |
164 | /**
165 | *
166 | */
167 | val lineNumber: Int,
168 |
169 | /**
170 | *
171 | */
172 | val columnNumber: Int
173 | )
174 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/emulation/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.emulation
2 |
3 | /**
4 | * Screen orientation.
5 | *
6 | * @link [Emulation#ScreenOrientation](https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-ScreenOrientation) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class ScreenOrientation(
11 | /**
12 | * Orientation type.
13 | */
14 | val type: String,
15 |
16 | /**
17 | * Orientation angle.
18 | */
19 | val angle: Int
20 | )
21 |
22 | /**
23 | *
24 | *
25 | * @link [Emulation#DisplayFeature](https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-DisplayFeature) type documentation.
26 | */
27 |
28 | @kotlinx.serialization.Serializable
29 | data class DisplayFeature(
30 | /**
31 | * Orientation of a display feature in relation to screen
32 | */
33 | val orientation: String,
34 |
35 | /**
36 | * The offset from the screen origin in either the x (for vertical
37 | orientation) or y (for horizontal orientation) direction.
38 | */
39 | val offset: Int,
40 |
41 | /**
42 | * A display feature may mask content such that it is not physically
43 | displayed - this length along with the offset describes this area.
44 | A display feature that only splits content will have a 0 mask_length.
45 | */
46 | val maskLength: Int
47 | )
48 |
49 | /**
50 | *
51 | *
52 | * @link [Emulation#MediaFeature](https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-MediaFeature) type documentation.
53 | */
54 |
55 | @kotlinx.serialization.Serializable
56 | data class MediaFeature(
57 | /**
58 | *
59 | */
60 | val name: String,
61 |
62 | /**
63 | *
64 | */
65 | val value: String
66 | )
67 |
68 | /**
69 | * advance: If the scheduler runs out of immediate work, the virtual time base may fast forward to
70 | allow the next delayed task (if any) to run; pause: The virtual time base may not advance;
71 | pauseIfNetworkFetchesPending: The virtual time base may not advance if there are any pending
72 | resource fetches.
73 | *
74 | * @link [Emulation#VirtualTimePolicy](https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-VirtualTimePolicy) type documentation.
75 | */
76 | @kotlinx.serialization.Serializable
77 | enum class VirtualTimePolicy {
78 | @kotlinx.serialization.SerialName("advance")
79 | ADVANCE,
80 |
81 | @kotlinx.serialization.SerialName("pause")
82 | PAUSE,
83 |
84 | @kotlinx.serialization.SerialName("pauseIfNetworkFetchesPending")
85 | PAUSEIFNETWORKFETCHESPENDING;
86 | }
87 |
88 | /**
89 | * Used to specify User Agent Cient Hints to emulate. See https://wicg.github.io/ua-client-hints
90 | *
91 | * @link [Emulation#UserAgentBrandVersion](https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-UserAgentBrandVersion) type documentation.
92 | */
93 |
94 | @kotlinx.serialization.Serializable
95 | data class UserAgentBrandVersion(
96 | /**
97 | *
98 | */
99 | val brand: String,
100 |
101 | /**
102 | *
103 | */
104 | val version: String
105 | )
106 |
107 | /**
108 | * Used to specify User Agent Cient Hints to emulate. See https://wicg.github.io/ua-client-hints
109 | Missing optional values will be filled in by the target with what it would normally use.
110 | *
111 | * @link [Emulation#UserAgentMetadata](https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-UserAgentMetadata) type documentation.
112 | */
113 |
114 | @kotlinx.serialization.Serializable
115 | data class UserAgentMetadata(
116 | /**
117 | *
118 | */
119 | val brands: List? = null,
120 |
121 | /**
122 | *
123 | */
124 | val fullVersion: String? = null,
125 |
126 | /**
127 | *
128 | */
129 | val platform: String,
130 |
131 | /**
132 | *
133 | */
134 | val platformVersion: String,
135 |
136 | /**
137 | *
138 | */
139 | val architecture: String,
140 |
141 | /**
142 | *
143 | */
144 | val model: String,
145 |
146 | /**
147 | *
148 | */
149 | val mobile: Boolean
150 | )
151 |
152 | /**
153 | * Enum of image types that can be disabled.
154 | *
155 | * @link [Emulation#DisabledImageType](https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-DisabledImageType) type documentation.
156 | */
157 | @kotlinx.serialization.Serializable
158 | enum class DisabledImageType {
159 | @kotlinx.serialization.SerialName("avif")
160 | AVIF,
161 |
162 | @kotlinx.serialization.SerialName("webp")
163 | WEBP;
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/protocol/websocket/WebSocketFramesStream.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.protocol.websocket
2 |
3 | import io.reactivex.rxjava3.core.BackpressureStrategy
4 | import io.reactivex.rxjava3.core.Flowable
5 | import io.reactivex.rxjava3.core.Single
6 | import io.reactivex.rxjava3.schedulers.Schedulers
7 | import io.reactivex.rxjava3.subjects.ReplaySubject
8 | import io.reactivex.rxjava3.subjects.Subject
9 | import kotlinx.serialization.KSerializer
10 | import okhttp3.OkHttpClient
11 | import okhttp3.Request
12 | import okhttp3.Response
13 | import okhttp3.WebSocket
14 | import okhttp3.WebSocketListener
15 | import org.slf4j.LoggerFactory
16 | import java.io.Closeable
17 | import java.io.EOFException
18 |
19 | /**
20 | * WebSocketFramesStream represents connection to remote WebSocket endpoint of the DevTools Protocol
21 | * (either inspectable page debugger url http://localhost:9222/json or browser debugger url http://localhost:9222/json/version)
22 | *
23 | * @param webSocketUri WebSocket debugger uri to connect to
24 | * @param framesBufferSize Frames buffer size (how many [ResponseFrame]s will be replayed prior to subscribing to stream)
25 | * @param mapper FrameMapper that will serialize/deserialize frames exchanged by protocol
26 | * @param webSocketClient WebSocket client for exchanging WebSocket frames.
27 | */
28 | class WebSocketFramesStream(
29 | webSocketUri: String,
30 | framesBufferSize: Int,
31 | private val mapper: FrameMapper,
32 | webSocketClient: OkHttpClient
33 | ) : WebSocketListener(), Closeable, AutoCloseable {
34 | private val messages: Subject = ReplaySubject.createWithSize(framesBufferSize)
35 | private val connection: WebSocket = webSocketClient.newWebSocket(Request.Builder().url(webSocketUri).build(), this)
36 | private val client: OkHttpClient = webSocketClient
37 |
38 | /**
39 | * onMessage is called when new frame arrives on WebSocket.
40 | */
41 | override fun onMessage(webSocket: WebSocket, text: String) {
42 | messages.onNext(mapper.deserializeWebSocketMessage(text))
43 | }
44 |
45 | /**
46 | * onClosed is called when WebSocket is being closed.
47 | */
48 | override fun onClosed(webSocket: WebSocket, code: Int, reason: String): Unit = closeSilently()
49 |
50 | /**
51 | * onFailure is called when WebSocket protocol error occurs.
52 | */
53 | override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
54 | if (t !is EOFException) {
55 | logger.warn("Caught WebSocket exception: $t")
56 | }
57 | }
58 |
59 | /**
60 | * Returns protocol response for given request frame (if any).
61 | */
62 | fun getResponse(requestFrame: RequestFrame, serializer: KSerializer): Single {
63 | return frames()
64 | .ofType(ResponseFrame::class.java)
65 | .filter { it.matches(requestFrame) }
66 | .map { frame -> mapper.deserializeResponseFrame(requestFrame, frame, serializer) }
67 | .subscribeOn(Schedulers.io())
68 | .firstOrError()
69 | }
70 |
71 | /**
72 | * Sends frame over the WebSocket connection.
73 | */
74 | fun send(frame: RequestFrame): Single {
75 | return Single.just(connection.send(mapper.serialize(frame)))
76 | }
77 |
78 | /**
79 | * Returns all frames that represent events from WebSocket connection.
80 | */
81 | fun eventFrames(): Flowable = frames().ofType(EventResponseFrame::class.java)
82 |
83 | /**
84 | * Returns all frames received from WebSocket connection.
85 | */
86 | fun frames(): Flowable = messages.toFlowable(BackpressureStrategy.BUFFER)
87 |
88 | /**
89 | * Closes WebSocket connection.
90 | */
91 | override fun close() {
92 | try {
93 | connection.close(1000, "Goodbye!")
94 | client.connectionPool.evictAll()
95 | client.dispatcher.executorService.shutdown()
96 | } catch (e: Exception) {
97 | logger.warn("Caught exception while closing WebSocket stream: ${e.message}")
98 | }
99 |
100 | try {
101 | closeSilently()
102 | } catch (e: Exception) {
103 | logger.warn("Caught exception while completing subject: ${e.message}")
104 | }
105 | }
106 |
107 | /**
108 | * Completes frames stream.
109 | */
110 | private fun closeSilently() {
111 | if (!(messages.hasComplete() || messages.hasThrowable())) {
112 | return messages.onComplete()
113 | }
114 | }
115 |
116 | companion object {
117 | private val logger = LoggerFactory.getLogger(WebSocketFramesStream::class.java)!!
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/webauthn/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.webauthn
2 |
3 | /**
4 | *
5 | *
6 | * @link [WebAuthn#AuthenticatorId](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-AuthenticatorId) type documentation.
7 | */
8 |
9 | typealias AuthenticatorId = String
10 |
11 | /**
12 | *
13 | *
14 | * @link [WebAuthn#AuthenticatorProtocol](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-AuthenticatorProtocol) type documentation.
15 | */
16 | @kotlinx.serialization.Serializable
17 | enum class AuthenticatorProtocol {
18 | @kotlinx.serialization.SerialName("u2f")
19 | U2F,
20 |
21 | @kotlinx.serialization.SerialName("ctap2")
22 | CTAP2;
23 | }
24 |
25 | /**
26 | *
27 | *
28 | * @link [WebAuthn#Ctap2Version](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-Ctap2Version) type documentation.
29 | */
30 | @kotlinx.serialization.Serializable
31 | enum class Ctap2Version {
32 | @kotlinx.serialization.SerialName("ctap2_0")
33 | CTAP2_0,
34 |
35 | @kotlinx.serialization.SerialName("ctap2_1")
36 | CTAP2_1;
37 | }
38 |
39 | /**
40 | *
41 | *
42 | * @link [WebAuthn#AuthenticatorTransport](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-AuthenticatorTransport) type documentation.
43 | */
44 | @kotlinx.serialization.Serializable
45 | enum class AuthenticatorTransport {
46 | @kotlinx.serialization.SerialName("usb")
47 | USB,
48 |
49 | @kotlinx.serialization.SerialName("nfc")
50 | NFC,
51 |
52 | @kotlinx.serialization.SerialName("ble")
53 | BLE,
54 |
55 | @kotlinx.serialization.SerialName("cable")
56 | CABLE,
57 |
58 | @kotlinx.serialization.SerialName("internal")
59 | INTERNAL;
60 | }
61 |
62 | /**
63 | *
64 | *
65 | * @link [WebAuthn#VirtualAuthenticatorOptions](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-VirtualAuthenticatorOptions) type documentation.
66 | */
67 |
68 | @kotlinx.serialization.Serializable
69 | data class VirtualAuthenticatorOptions(
70 | /**
71 | *
72 | */
73 | val protocol: AuthenticatorProtocol,
74 |
75 | /**
76 | * Defaults to ctap2_0. Ignored if |protocol| == u2f.
77 | */
78 | val ctap2Version: Ctap2Version? = null,
79 |
80 | /**
81 | *
82 | */
83 | val transport: AuthenticatorTransport,
84 |
85 | /**
86 | * Defaults to false.
87 | */
88 | val hasResidentKey: Boolean? = null,
89 |
90 | /**
91 | * Defaults to false.
92 | */
93 | val hasUserVerification: Boolean? = null,
94 |
95 | /**
96 | * If set to true, the authenticator will support the largeBlob extension.
97 | https://w3c.github.io/webauthn#largeBlob
98 | Defaults to false.
99 | */
100 | val hasLargeBlob: Boolean? = null,
101 |
102 | /**
103 | * If set to true, tests of user presence will succeed immediately.
104 | Otherwise, they will not be resolved. Defaults to true.
105 | */
106 | val automaticPresenceSimulation: Boolean? = null,
107 |
108 | /**
109 | * Sets whether User Verification succeeds or fails for an authenticator.
110 | Defaults to false.
111 | */
112 | val isUserVerified: Boolean? = null
113 | )
114 |
115 | /**
116 | *
117 | *
118 | * @link [WebAuthn#Credential](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-Credential) type documentation.
119 | */
120 |
121 | @kotlinx.serialization.Serializable
122 | data class Credential(
123 | /**
124 | *
125 | */
126 | val credentialId: String,
127 |
128 | /**
129 | *
130 | */
131 | val isResidentCredential: Boolean,
132 |
133 | /**
134 | * Relying Party ID the credential is scoped to. Must be set when adding a
135 | credential.
136 | */
137 | val rpId: String? = null,
138 |
139 | /**
140 | * The ECDSA P-256 private key in PKCS#8 format. (Encoded as a base64 string when passed over JSON)
141 | */
142 | val privateKey: String,
143 |
144 | /**
145 | * An opaque byte sequence with a maximum size of 64 bytes mapping the
146 | credential to a specific user. (Encoded as a base64 string when passed over JSON)
147 | */
148 | val userHandle: String? = null,
149 |
150 | /**
151 | * Signature counter. This is incremented by one for each successful
152 | assertion.
153 | See https://w3c.github.io/webauthn/#signature-counter
154 | */
155 | val signCount: Int,
156 |
157 | /**
158 | * The large blob associated with the credential.
159 | See https://w3c.github.io/webauthn/#sctn-large-blob-extension (Encoded as a base64 string when passed over JSON)
160 | */
161 | val largeBlob: String? = null
162 | )
163 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/log/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.log
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * Provides access to log entries.
7 | *
8 | * @link Protocol [Log](https://chromedevtools.github.io/devtools-protocol/tot/Log) domain documentation.
9 | */
10 |
11 | class LogDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
12 | pl.wendigo.chrome.protocol.Domain("Log", """Provides access to log entries.""", connection) {
13 | /**
14 | * Clears the log.
15 | *
16 | * @link Protocol [Log#clear](https://chromedevtools.github.io/devtools-protocol/tot/Log#method-clear) method documentation.
17 | */
18 |
19 | fun clear(): io.reactivex.rxjava3.core.Single = connection.request("Log.clear", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
20 |
21 | /**
22 | * Disables log domain, prevents further log entries from being reported to the client.
23 | *
24 | * @link Protocol [Log#disable](https://chromedevtools.github.io/devtools-protocol/tot/Log#method-disable) method documentation.
25 | */
26 |
27 | fun disable(): io.reactivex.rxjava3.core.Single = connection.request("Log.disable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
28 |
29 | /**
30 | * Enables log domain, sends the entries collected so far to the client by means of the
31 | `entryAdded` notification.
32 | *
33 | * @link Protocol [Log#enable](https://chromedevtools.github.io/devtools-protocol/tot/Log#method-enable) method documentation.
34 | */
35 |
36 | fun enable(): io.reactivex.rxjava3.core.Single = connection.request("Log.enable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
37 |
38 | /**
39 | * start violation reporting.
40 | *
41 | * @link Protocol [Log#startViolationsReport](https://chromedevtools.github.io/devtools-protocol/tot/Log#method-startViolationsReport) method documentation.
42 | */
43 |
44 | fun startViolationsReport(input: StartViolationsReportRequest): io.reactivex.rxjava3.core.Single = connection.request("Log.startViolationsReport", Json.encodeToJsonElement(StartViolationsReportRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
45 |
46 | /**
47 | * Stop violation reporting.
48 | *
49 | * @link Protocol [Log#stopViolationsReport](https://chromedevtools.github.io/devtools-protocol/tot/Log#method-stopViolationsReport) method documentation.
50 | */
51 |
52 | fun stopViolationsReport(): io.reactivex.rxjava3.core.Single = connection.request("Log.stopViolationsReport", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
53 |
54 | /**
55 | * Issued when new message was logged.
56 | */
57 | fun entryAdded(): io.reactivex.rxjava3.core.Flowable = connection.events("Log.entryAdded", EntryAddedEvent.serializer())
58 |
59 | /**
60 | * Returns list of dependant domains that should be enabled prior to enabling this domain.
61 | */
62 | override fun getDependencies(): List {
63 | return arrayListOf(
64 | pl.wendigo.chrome.api.runtime.RuntimeDomain(connection),
65 | pl.wendigo.chrome.api.network.NetworkDomain(connection),
66 | )
67 | }
68 | }
69 |
70 | /**
71 | * Represents request frame that can be used with [Log#startViolationsReport](https://chromedevtools.github.io/devtools-protocol/tot/Log#method-startViolationsReport) operation call.
72 | *
73 | * start violation reporting.
74 | * @link [Log#startViolationsReport](https://chromedevtools.github.io/devtools-protocol/tot/Log#method-startViolationsReport) method documentation.
75 | * @see [LogDomain.startViolationsReport]
76 | */
77 | @kotlinx.serialization.Serializable
78 | data class StartViolationsReportRequest(
79 | /**
80 | * Configuration for violations.
81 | */
82 | val config: List
83 |
84 | )
85 |
86 | /**
87 | * Issued when new message was logged.
88 | *
89 | * @link [Log#entryAdded](https://chromedevtools.github.io/devtools-protocol/tot/Log#event-entryAdded) event documentation.
90 | */
91 | @kotlinx.serialization.Serializable
92 | data class EntryAddedEvent(
93 | /**
94 | * The entry.
95 | */
96 | val entry: LogEntry
97 |
98 | ) : pl.wendigo.chrome.protocol.Event {
99 | override fun domain() = "Log"
100 | override fun eventName() = "entryAdded"
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/indexeddb/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.indexeddb
2 |
3 | /**
4 | * Database with an array of object stores.
5 | *
6 | * @link [IndexedDB#DatabaseWithObjectStores](https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-DatabaseWithObjectStores) type documentation.
7 | */
8 |
9 | @kotlinx.serialization.Serializable
10 | data class DatabaseWithObjectStores(
11 | /**
12 | * Database name.
13 | */
14 | val name: String,
15 |
16 | /**
17 | * Database version (type is not 'integer', as the standard
18 | requires the version number to be 'unsigned long long')
19 | */
20 | val version: Double,
21 |
22 | /**
23 | * Object stores in this database.
24 | */
25 | val objectStores: List
26 | )
27 |
28 | /**
29 | * Object store.
30 | *
31 | * @link [IndexedDB#ObjectStore](https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-ObjectStore) type documentation.
32 | */
33 |
34 | @kotlinx.serialization.Serializable
35 | data class ObjectStore(
36 | /**
37 | * Object store name.
38 | */
39 | val name: String,
40 |
41 | /**
42 | * Object store key path.
43 | */
44 | val keyPath: KeyPath,
45 |
46 | /**
47 | * If true, object store has auto increment flag set.
48 | */
49 | val autoIncrement: Boolean,
50 |
51 | /**
52 | * Indexes in this object store.
53 | */
54 | val indexes: List
55 | )
56 |
57 | /**
58 | * Object store index.
59 | *
60 | * @link [IndexedDB#ObjectStoreIndex](https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-ObjectStoreIndex) type documentation.
61 | */
62 |
63 | @kotlinx.serialization.Serializable
64 | data class ObjectStoreIndex(
65 | /**
66 | * Index name.
67 | */
68 | val name: String,
69 |
70 | /**
71 | * Index key path.
72 | */
73 | val keyPath: KeyPath,
74 |
75 | /**
76 | * If true, index is unique.
77 | */
78 | val unique: Boolean,
79 |
80 | /**
81 | * If true, index allows multiple entries for a key.
82 | */
83 | val multiEntry: Boolean
84 | )
85 |
86 | /**
87 | * Key.
88 | *
89 | * @link [IndexedDB#Key](https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-Key) type documentation.
90 | */
91 |
92 | @kotlinx.serialization.Serializable
93 | data class Key(
94 | /**
95 | * Key type.
96 | */
97 | val type: String,
98 |
99 | /**
100 | * Number value.
101 | */
102 | val number: Double? = null,
103 |
104 | /**
105 | * String value.
106 | */
107 | val string: String? = null,
108 |
109 | /**
110 | * Date value.
111 | */
112 | val date: Double? = null,
113 |
114 | /**
115 | * Array value.
116 | */
117 | val array: List? = null
118 | )
119 |
120 | /**
121 | * Key range.
122 | *
123 | * @link [IndexedDB#KeyRange](https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-KeyRange) type documentation.
124 | */
125 |
126 | @kotlinx.serialization.Serializable
127 | data class KeyRange(
128 | /**
129 | * Lower bound.
130 | */
131 | val lower: Key? = null,
132 |
133 | /**
134 | * Upper bound.
135 | */
136 | val upper: Key? = null,
137 |
138 | /**
139 | * If true lower bound is open.
140 | */
141 | val lowerOpen: Boolean,
142 |
143 | /**
144 | * If true upper bound is open.
145 | */
146 | val upperOpen: Boolean
147 | )
148 |
149 | /**
150 | * Data entry.
151 | *
152 | * @link [IndexedDB#DataEntry](https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-DataEntry) type documentation.
153 | */
154 |
155 | @kotlinx.serialization.Serializable
156 | data class DataEntry(
157 | /**
158 | * Key object.
159 | */
160 | val key: pl.wendigo.chrome.api.runtime.RemoteObject,
161 |
162 | /**
163 | * Primary key object.
164 | */
165 | val primaryKey: pl.wendigo.chrome.api.runtime.RemoteObject,
166 |
167 | /**
168 | * Value object.
169 | */
170 | val value: pl.wendigo.chrome.api.runtime.RemoteObject
171 | )
172 |
173 | /**
174 | * Key path.
175 | *
176 | * @link [IndexedDB#KeyPath](https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-KeyPath) type documentation.
177 | */
178 |
179 | @kotlinx.serialization.Serializable
180 | data class KeyPath(
181 | /**
182 | * Key path type.
183 | */
184 | val type: String,
185 |
186 | /**
187 | * String value.
188 | */
189 | val string: String? = null,
190 |
191 | /**
192 | * Array value.
193 | */
194 | val array: List? = null
195 | )
196 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/layertree/Types.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.layertree
2 |
3 | /**
4 | * Unique Layer identifier.
5 | *
6 | * @link [LayerTree#LayerId](https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-LayerId) type documentation.
7 | */
8 |
9 | typealias LayerId = String
10 |
11 | /**
12 | * Unique snapshot identifier.
13 | *
14 | * @link [LayerTree#SnapshotId](https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-SnapshotId) type documentation.
15 | */
16 |
17 | typealias SnapshotId = String
18 |
19 | /**
20 | * Rectangle where scrolling happens on the main thread.
21 | *
22 | * @link [LayerTree#ScrollRect](https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-ScrollRect) type documentation.
23 | */
24 |
25 | @kotlinx.serialization.Serializable
26 | data class ScrollRect(
27 | /**
28 | * Rectangle itself.
29 | */
30 | val rect: pl.wendigo.chrome.api.dom.Rect,
31 |
32 | /**
33 | * Reason for rectangle to force scrolling on the main thread
34 | */
35 | val type: String
36 | )
37 |
38 | /**
39 | * Sticky position constraints.
40 | *
41 | * @link [LayerTree#StickyPositionConstraint](https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-StickyPositionConstraint) type documentation.
42 | */
43 |
44 | @kotlinx.serialization.Serializable
45 | data class StickyPositionConstraint(
46 | /**
47 | * Layout rectangle of the sticky element before being shifted
48 | */
49 | val stickyBoxRect: pl.wendigo.chrome.api.dom.Rect,
50 |
51 | /**
52 | * Layout rectangle of the containing block of the sticky element
53 | */
54 | val containingBlockRect: pl.wendigo.chrome.api.dom.Rect,
55 |
56 | /**
57 | * The nearest sticky layer that shifts the sticky box
58 | */
59 | val nearestLayerShiftingStickyBox: LayerId? = null,
60 |
61 | /**
62 | * The nearest sticky layer that shifts the containing block
63 | */
64 | val nearestLayerShiftingContainingBlock: LayerId? = null
65 | )
66 |
67 | /**
68 | * Serialized fragment of layer picture along with its offset within the layer.
69 | *
70 | * @link [LayerTree#PictureTile](https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-PictureTile) type documentation.
71 | */
72 |
73 | @kotlinx.serialization.Serializable
74 | data class PictureTile(
75 | /**
76 | * Offset from owning layer left boundary
77 | */
78 | val x: Double,
79 |
80 | /**
81 | * Offset from owning layer top boundary
82 | */
83 | val y: Double,
84 |
85 | /**
86 | * Base64-encoded snapshot data. (Encoded as a base64 string when passed over JSON)
87 | */
88 | val picture: String
89 | )
90 |
91 | /**
92 | * Information about a compositing layer.
93 | *
94 | * @link [LayerTree#Layer](https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-Layer) type documentation.
95 | */
96 |
97 | @kotlinx.serialization.Serializable
98 | data class Layer(
99 | /**
100 | * The unique id for this layer.
101 | */
102 | val layerId: LayerId,
103 |
104 | /**
105 | * The id of parent (not present for root).
106 | */
107 | val parentLayerId: LayerId? = null,
108 |
109 | /**
110 | * The backend id for the node associated with this layer.
111 | */
112 | val backendNodeId: pl.wendigo.chrome.api.dom.BackendNodeId? = null,
113 |
114 | /**
115 | * Offset from parent layer, X coordinate.
116 | */
117 | val offsetX: Double,
118 |
119 | /**
120 | * Offset from parent layer, Y coordinate.
121 | */
122 | val offsetY: Double,
123 |
124 | /**
125 | * Layer width.
126 | */
127 | val width: Double,
128 |
129 | /**
130 | * Layer height.
131 | */
132 | val height: Double,
133 |
134 | /**
135 | * Transformation matrix for layer, default is identity matrix
136 | */
137 | val transform: List? = null,
138 |
139 | /**
140 | * Transform anchor point X, absent if no transform specified
141 | */
142 | val anchorX: Double? = null,
143 |
144 | /**
145 | * Transform anchor point Y, absent if no transform specified
146 | */
147 | val anchorY: Double? = null,
148 |
149 | /**
150 | * Transform anchor point Z, absent if no transform specified
151 | */
152 | val anchorZ: Double? = null,
153 |
154 | /**
155 | * Indicates how many time this layer has painted.
156 | */
157 | val paintCount: Int,
158 |
159 | /**
160 | * Indicates whether this layer hosts any content, rather than being used for
161 | transform/scrolling purposes only.
162 | */
163 | val drawsContent: Boolean,
164 |
165 | /**
166 | * Set if layer is not visible.
167 | */
168 | val invisible: Boolean? = null,
169 |
170 | /**
171 | * Rectangles scrolling on main thread only.
172 | */
173 | val scrollRects: List? = null,
174 |
175 | /**
176 | * Sticky position constraint information
177 | */
178 | val stickyPositionConstraint: StickyPositionConstraint? = null
179 | )
180 |
181 | /**
182 | * Array of timings, one per paint step.
183 | *
184 | * @link [LayerTree#PaintProfile](https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-PaintProfile) type documentation.
185 | */
186 |
187 | typealias PaintProfile = List
188 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/io/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.io
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * Input/Output operations for streams produced by DevTools.
7 | *
8 | * @link Protocol [IO](https://chromedevtools.github.io/devtools-protocol/tot/IO) domain documentation.
9 | */
10 |
11 | class IODomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
12 | pl.wendigo.chrome.protocol.Domain("IO", """Input/Output operations for streams produced by DevTools.""", connection) {
13 | /**
14 | * Close the stream, discard any temporary backing storage.
15 | *
16 | * @link Protocol [IO#close](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-close) method documentation.
17 | */
18 |
19 | fun close(input: CloseRequest): io.reactivex.rxjava3.core.Single = connection.request("IO.close", Json.encodeToJsonElement(CloseRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
20 |
21 | /**
22 | * Read a chunk of the stream
23 | *
24 | * @link Protocol [IO#read](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-read) method documentation.
25 | */
26 |
27 | fun read(input: ReadRequest): io.reactivex.rxjava3.core.Single = connection.request("IO.read", Json.encodeToJsonElement(ReadRequest.serializer(), input), ReadResponse.serializer())
28 |
29 | /**
30 | * Return UUID of Blob object specified by a remote object id.
31 | *
32 | * @link Protocol [IO#resolveBlob](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-resolveBlob) method documentation.
33 | */
34 |
35 | fun resolveBlob(input: ResolveBlobRequest): io.reactivex.rxjava3.core.Single = connection.request("IO.resolveBlob", Json.encodeToJsonElement(ResolveBlobRequest.serializer(), input), ResolveBlobResponse.serializer())
36 | }
37 |
38 | /**
39 | * Represents request frame that can be used with [IO#close](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-close) operation call.
40 | *
41 | * Close the stream, discard any temporary backing storage.
42 | * @link [IO#close](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-close) method documentation.
43 | * @see [IODomain.close]
44 | */
45 | @kotlinx.serialization.Serializable
46 | data class CloseRequest(
47 | /**
48 | * Handle of the stream to close.
49 | */
50 | val handle: StreamHandle
51 |
52 | )
53 |
54 | /**
55 | * Represents request frame that can be used with [IO#read](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-read) operation call.
56 | *
57 | * Read a chunk of the stream
58 | * @link [IO#read](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-read) method documentation.
59 | * @see [IODomain.read]
60 | */
61 | @kotlinx.serialization.Serializable
62 | data class ReadRequest(
63 | /**
64 | * Handle of the stream to read.
65 | */
66 | val handle: StreamHandle,
67 |
68 | /**
69 | * Seek to the specified offset before reading (if not specificed, proceed with offset
70 | following the last read). Some types of streams may only support sequential reads.
71 | */
72 | val offset: Int? = null,
73 |
74 | /**
75 | * Maximum number of bytes to read (left upon the agent discretion if not specified).
76 | */
77 | val size: Int? = null
78 |
79 | )
80 |
81 | /**
82 | * Represents response frame that is returned from [IO#read](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-read) operation call.
83 | * Read a chunk of the stream
84 | *
85 |
86 | * @link [IO#read](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-read) method documentation.
87 | * @see [IODomain.read]
88 | */
89 | @kotlinx.serialization.Serializable
90 | data class ReadResponse(
91 | /**
92 | * Set if the data is base64-encoded
93 | */
94 | val base64Encoded: Boolean? = null,
95 |
96 | /**
97 | * Data that were read.
98 | */
99 | val data: String,
100 |
101 | /**
102 | * Set if the end-of-file condition occured while reading.
103 | */
104 | val eof: Boolean
105 |
106 | )
107 |
108 | /**
109 | * Represents request frame that can be used with [IO#resolveBlob](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-resolveBlob) operation call.
110 | *
111 | * Return UUID of Blob object specified by a remote object id.
112 | * @link [IO#resolveBlob](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-resolveBlob) method documentation.
113 | * @see [IODomain.resolveBlob]
114 | */
115 | @kotlinx.serialization.Serializable
116 | data class ResolveBlobRequest(
117 | /**
118 | * Object id of a Blob object wrapper.
119 | */
120 | val objectId: pl.wendigo.chrome.api.runtime.RemoteObjectId
121 |
122 | )
123 |
124 | /**
125 | * Represents response frame that is returned from [IO#resolveBlob](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-resolveBlob) operation call.
126 | * Return UUID of Blob object specified by a remote object id.
127 | *
128 |
129 | * @link [IO#resolveBlob](https://chromedevtools.github.io/devtools-protocol/tot/IO#method-resolveBlob) method documentation.
130 | * @see [IODomain.resolveBlob]
131 | */
132 | @kotlinx.serialization.Serializable
133 | data class ResolveBlobResponse(
134 | /**
135 | * UUID of the specified Blob.
136 | */
137 | val uuid: String
138 |
139 | )
140 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/performance/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.performance
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * PerformanceDomain represents Performance protocol domain request/response operations and events that can be captured.
7 | *
8 | * @link Protocol [Performance](https://chromedevtools.github.io/devtools-protocol/tot/Performance) domain documentation.
9 | */
10 |
11 | class PerformanceDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
12 | pl.wendigo.chrome.protocol.Domain("Performance", """""", connection) {
13 | /**
14 | * Disable collecting and reporting metrics.
15 | *
16 | * @link Protocol [Performance#disable](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-disable) method documentation.
17 | */
18 |
19 | fun disable(): io.reactivex.rxjava3.core.Single = connection.request("Performance.disable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
20 |
21 | /**
22 | * Enable collecting and reporting metrics.
23 | *
24 | * @link Protocol [Performance#enable](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-enable) method documentation.
25 | */
26 |
27 | fun enable(input: EnableRequest): io.reactivex.rxjava3.core.Single = connection.request("Performance.enable", Json.encodeToJsonElement(EnableRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
28 |
29 | /**
30 | * Sets time domain to use for collecting and reporting duration metrics.
31 | Note that this must be called before enabling metrics collection. Calling
32 | this method while metrics collection is enabled returns an error.
33 | *
34 | * @link Protocol [Performance#setTimeDomain](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-setTimeDomain) method documentation.
35 | */
36 | @Deprecated(level = DeprecationLevel.WARNING, message = "setTimeDomain is deprecated.")
37 | @pl.wendigo.chrome.protocol.Experimental
38 | fun setTimeDomain(input: SetTimeDomainRequest): io.reactivex.rxjava3.core.Single = connection.request("Performance.setTimeDomain", Json.encodeToJsonElement(SetTimeDomainRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
39 |
40 | /**
41 | * Retrieve current values of run-time metrics.
42 | *
43 | * @link Protocol [Performance#getMetrics](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-getMetrics) method documentation.
44 | */
45 |
46 | fun getMetrics(): io.reactivex.rxjava3.core.Single = connection.request("Performance.getMetrics", null, GetMetricsResponse.serializer())
47 |
48 | /**
49 | * Current values of the metrics.
50 | */
51 | fun metrics(): io.reactivex.rxjava3.core.Flowable = connection.events("Performance.metrics", MetricsEvent.serializer())
52 | }
53 |
54 | /**
55 | * Represents request frame that can be used with [Performance#enable](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-enable) operation call.
56 | *
57 | * Enable collecting and reporting metrics.
58 | * @link [Performance#enable](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-enable) method documentation.
59 | * @see [PerformanceDomain.enable]
60 | */
61 | @kotlinx.serialization.Serializable
62 | data class EnableRequest(
63 | /**
64 | * Time domain to use for collecting and reporting duration metrics.
65 | */
66 | val timeDomain: String? = null
67 |
68 | )
69 |
70 | /**
71 | * Represents request frame that can be used with [Performance#setTimeDomain](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-setTimeDomain) operation call.
72 | *
73 | * Sets time domain to use for collecting and reporting duration metrics.
74 | Note that this must be called before enabling metrics collection. Calling
75 | this method while metrics collection is enabled returns an error.
76 | * @link [Performance#setTimeDomain](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-setTimeDomain) method documentation.
77 | * @see [PerformanceDomain.setTimeDomain]
78 | */
79 | @kotlinx.serialization.Serializable
80 | data class SetTimeDomainRequest(
81 | /**
82 | * Time domain
83 | */
84 | val timeDomain: String
85 |
86 | )
87 |
88 | /**
89 | * Represents response frame that is returned from [Performance#getMetrics](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-getMetrics) operation call.
90 | * Retrieve current values of run-time metrics.
91 | *
92 |
93 | * @link [Performance#getMetrics](https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-getMetrics) method documentation.
94 | * @see [PerformanceDomain.getMetrics]
95 | */
96 | @kotlinx.serialization.Serializable
97 | data class GetMetricsResponse(
98 | /**
99 | * Current values for run-time metrics.
100 | */
101 | val metrics: List
102 |
103 | )
104 |
105 | /**
106 | * Current values of the metrics.
107 | *
108 | * @link [Performance#metrics](https://chromedevtools.github.io/devtools-protocol/tot/Performance#event-metrics) event documentation.
109 | */
110 | @kotlinx.serialization.Serializable
111 | data class MetricsEvent(
112 | /**
113 | * Current values of the metrics.
114 | */
115 | val metrics: List,
116 |
117 | /**
118 | * Timestamp title.
119 | */
120 | val title: String
121 |
122 | ) : pl.wendigo.chrome.protocol.Event {
123 | override fun domain() = "Performance"
124 | override fun eventName() = "metrics"
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/database/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.database
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * DatabaseDomain represents Database protocol domain request/response operations and events that can be captured.
7 | *
8 | * This API is marked as experimental in protocol definition and can change in the future.
9 | * @link Protocol [Database](https://chromedevtools.github.io/devtools-protocol/tot/Database) domain documentation.
10 | */
11 | @pl.wendigo.chrome.protocol.Experimental
12 | class DatabaseDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
13 | pl.wendigo.chrome.protocol.Domain("Database", """""", connection) {
14 | /**
15 | * Disables database tracking, prevents database events from being sent to the client.
16 | *
17 | * @link Protocol [Database#disable](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-disable) method documentation.
18 | */
19 |
20 | fun disable(): io.reactivex.rxjava3.core.Single = connection.request("Database.disable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
21 |
22 | /**
23 | * Enables database tracking, database events will now be delivered to the client.
24 | *
25 | * @link Protocol [Database#enable](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-enable) method documentation.
26 | */
27 |
28 | fun enable(): io.reactivex.rxjava3.core.Single = connection.request("Database.enable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
29 |
30 | /**
31 | *
32 | *
33 | * @link Protocol [Database#executeSQL](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-executeSQL) method documentation.
34 | */
35 |
36 | fun executeSQL(input: ExecuteSQLRequest): io.reactivex.rxjava3.core.Single = connection.request("Database.executeSQL", Json.encodeToJsonElement(ExecuteSQLRequest.serializer(), input), ExecuteSQLResponse.serializer())
37 |
38 | /**
39 | *
40 | *
41 | * @link Protocol [Database#getDatabaseTableNames](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-getDatabaseTableNames) method documentation.
42 | */
43 |
44 | fun getDatabaseTableNames(input: GetDatabaseTableNamesRequest): io.reactivex.rxjava3.core.Single = connection.request("Database.getDatabaseTableNames", Json.encodeToJsonElement(GetDatabaseTableNamesRequest.serializer(), input), GetDatabaseTableNamesResponse.serializer())
45 |
46 | /**
47 | * Returns observable capturing all Database.addDatabase events.
48 | */
49 | fun addDatabase(): io.reactivex.rxjava3.core.Flowable = connection.events("Database.addDatabase", AddDatabaseEvent.serializer())
50 | }
51 |
52 | /**
53 | * Represents request frame that can be used with [Database#executeSQL](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-executeSQL) operation call.
54 | *
55 | *
56 | * @link [Database#executeSQL](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-executeSQL) method documentation.
57 | * @see [DatabaseDomain.executeSQL]
58 | */
59 | @kotlinx.serialization.Serializable
60 | data class ExecuteSQLRequest(
61 | /**
62 | *
63 | */
64 | val databaseId: DatabaseId,
65 |
66 | /**
67 | *
68 | */
69 | val query: String
70 |
71 | )
72 |
73 | /**
74 | * Represents response frame that is returned from [Database#executeSQL](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-executeSQL) operation call.
75 | *
76 | *
77 |
78 | * @link [Database#executeSQL](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-executeSQL) method documentation.
79 | * @see [DatabaseDomain.executeSQL]
80 | */
81 | @kotlinx.serialization.Serializable
82 | data class ExecuteSQLResponse(
83 | /**
84 | *
85 | */
86 | val columnNames: List? = null,
87 |
88 | /**
89 | *
90 | */
91 | val values: List? = null,
92 |
93 | /**
94 | *
95 | */
96 | val sqlError: Error? = null
97 |
98 | )
99 |
100 | /**
101 | * Represents request frame that can be used with [Database#getDatabaseTableNames](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-getDatabaseTableNames) operation call.
102 | *
103 | *
104 | * @link [Database#getDatabaseTableNames](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-getDatabaseTableNames) method documentation.
105 | * @see [DatabaseDomain.getDatabaseTableNames]
106 | */
107 | @kotlinx.serialization.Serializable
108 | data class GetDatabaseTableNamesRequest(
109 | /**
110 | *
111 | */
112 | val databaseId: DatabaseId
113 |
114 | )
115 |
116 | /**
117 | * Represents response frame that is returned from [Database#getDatabaseTableNames](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-getDatabaseTableNames) operation call.
118 | *
119 | *
120 |
121 | * @link [Database#getDatabaseTableNames](https://chromedevtools.github.io/devtools-protocol/tot/Database#method-getDatabaseTableNames) method documentation.
122 | * @see [DatabaseDomain.getDatabaseTableNames]
123 | */
124 | @kotlinx.serialization.Serializable
125 | data class GetDatabaseTableNamesResponse(
126 | /**
127 | *
128 | */
129 | val tableNames: List
130 |
131 | )
132 |
133 | /**
134 | *
135 | *
136 | * @link [Database#addDatabase](https://chromedevtools.github.io/devtools-protocol/tot/Database#event-addDatabase) event documentation.
137 | */
138 | @kotlinx.serialization.Serializable
139 | data class AddDatabaseEvent(
140 | /**
141 | *
142 | */
143 | val database: Database
144 |
145 | ) : pl.wendigo.chrome.protocol.Event {
146 | override fun domain() = "Database"
147 | override fun eventName() = "addDatabase"
148 | }
149 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/media/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.media
2 |
3 | /**
4 | * This domain allows detailed inspection of media elements
5 | *
6 | * This API is marked as experimental in protocol definition and can change in the future.
7 | * @link Protocol [Media](https://chromedevtools.github.io/devtools-protocol/tot/Media) domain documentation.
8 | */
9 | @pl.wendigo.chrome.protocol.Experimental
10 | class MediaDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
11 | pl.wendigo.chrome.protocol.Domain("Media", """This domain allows detailed inspection of media elements""", connection) {
12 | /**
13 | * Enables the Media domain
14 | *
15 | * @link Protocol [Media#enable](https://chromedevtools.github.io/devtools-protocol/tot/Media#method-enable) method documentation.
16 | */
17 |
18 | fun enable(): io.reactivex.rxjava3.core.Single = connection.request("Media.enable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
19 |
20 | /**
21 | * Disables the Media domain.
22 | *
23 | * @link Protocol [Media#disable](https://chromedevtools.github.io/devtools-protocol/tot/Media#method-disable) method documentation.
24 | */
25 |
26 | fun disable(): io.reactivex.rxjava3.core.Single = connection.request("Media.disable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
27 |
28 | /**
29 | * This can be called multiple times, and can be used to set / override /
30 | remove player properties. A null propValue indicates removal.
31 | */
32 | fun playerPropertiesChanged(): io.reactivex.rxjava3.core.Flowable = connection.events("Media.playerPropertiesChanged", PlayerPropertiesChangedEvent.serializer())
33 |
34 | /**
35 | * Send events as a list, allowing them to be batched on the browser for less
36 | congestion. If batched, events must ALWAYS be in chronological order.
37 | */
38 | fun playerEventsAdded(): io.reactivex.rxjava3.core.Flowable = connection.events("Media.playerEventsAdded", PlayerEventsAddedEvent.serializer())
39 |
40 | /**
41 | * Send a list of any messages that need to be delivered.
42 | */
43 | fun playerMessagesLogged(): io.reactivex.rxjava3.core.Flowable = connection.events("Media.playerMessagesLogged", PlayerMessagesLoggedEvent.serializer())
44 |
45 | /**
46 | * Send a list of any errors that need to be delivered.
47 | */
48 | fun playerErrorsRaised(): io.reactivex.rxjava3.core.Flowable = connection.events("Media.playerErrorsRaised", PlayerErrorsRaisedEvent.serializer())
49 |
50 | /**
51 | * Called whenever a player is created, or when a new agent joins and recieves
52 | a list of active players. If an agent is restored, it will recieve the full
53 | list of player ids and all events again.
54 | */
55 | fun playersCreated(): io.reactivex.rxjava3.core.Flowable = connection.events("Media.playersCreated", PlayersCreatedEvent.serializer())
56 | }
57 |
58 | /**
59 | * This can be called multiple times, and can be used to set / override /
60 | remove player properties. A null propValue indicates removal.
61 | *
62 | * @link [Media#playerPropertiesChanged](https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerPropertiesChanged) event documentation.
63 | */
64 | @kotlinx.serialization.Serializable
65 | data class PlayerPropertiesChangedEvent(
66 | /**
67 | *
68 | */
69 | val playerId: PlayerId,
70 |
71 | /**
72 | *
73 | */
74 | val properties: List
75 |
76 | ) : pl.wendigo.chrome.protocol.Event {
77 | override fun domain() = "Media"
78 | override fun eventName() = "playerPropertiesChanged"
79 | }
80 |
81 | /**
82 | * Send events as a list, allowing them to be batched on the browser for less
83 | congestion. If batched, events must ALWAYS be in chronological order.
84 | *
85 | * @link [Media#playerEventsAdded](https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerEventsAdded) event documentation.
86 | */
87 | @kotlinx.serialization.Serializable
88 | data class PlayerEventsAddedEvent(
89 | /**
90 | *
91 | */
92 | val playerId: PlayerId,
93 |
94 | /**
95 | *
96 | */
97 | val events: List
98 |
99 | ) : pl.wendigo.chrome.protocol.Event {
100 | override fun domain() = "Media"
101 | override fun eventName() = "playerEventsAdded"
102 | }
103 |
104 | /**
105 | * Send a list of any messages that need to be delivered.
106 | *
107 | * @link [Media#playerMessagesLogged](https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerMessagesLogged) event documentation.
108 | */
109 | @kotlinx.serialization.Serializable
110 | data class PlayerMessagesLoggedEvent(
111 | /**
112 | *
113 | */
114 | val playerId: PlayerId,
115 |
116 | /**
117 | *
118 | */
119 | val messages: List
120 |
121 | ) : pl.wendigo.chrome.protocol.Event {
122 | override fun domain() = "Media"
123 | override fun eventName() = "playerMessagesLogged"
124 | }
125 |
126 | /**
127 | * Send a list of any errors that need to be delivered.
128 | *
129 | * @link [Media#playerErrorsRaised](https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerErrorsRaised) event documentation.
130 | */
131 | @kotlinx.serialization.Serializable
132 | data class PlayerErrorsRaisedEvent(
133 | /**
134 | *
135 | */
136 | val playerId: PlayerId,
137 |
138 | /**
139 | *
140 | */
141 | val errors: List
142 |
143 | ) : pl.wendigo.chrome.protocol.Event {
144 | override fun domain() = "Media"
145 | override fun eventName() = "playerErrorsRaised"
146 | }
147 |
148 | /**
149 | * Called whenever a player is created, or when a new agent joins and recieves
150 | a list of active players. If an agent is restored, it will recieve the full
151 | list of player ids and all events again.
152 | *
153 | * @link [Media#playersCreated](https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playersCreated) event documentation.
154 | */
155 | @kotlinx.serialization.Serializable
156 | data class PlayersCreatedEvent(
157 | /**
158 | *
159 | */
160 | val players: List
161 |
162 | ) : pl.wendigo.chrome.protocol.Event {
163 | override fun domain() = "Media"
164 | override fun eventName() = "playersCreated"
165 | }
166 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/targets/Manager.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.targets
2 |
3 | import org.slf4j.Logger
4 | import org.slf4j.LoggerFactory
5 | import pl.wendigo.chrome.api.ProtocolDomains
6 | import pl.wendigo.chrome.api.target.AttachToTargetRequest
7 | import pl.wendigo.chrome.api.target.CloseTargetRequest
8 | import pl.wendigo.chrome.api.target.CreateBrowserContextRequest
9 | import pl.wendigo.chrome.api.target.CreateTargetRequest
10 | import pl.wendigo.chrome.api.target.DisposeBrowserContextRequest
11 | import pl.wendigo.chrome.api.target.GetTargetInfoRequest
12 | import pl.wendigo.chrome.api.target.SetDiscoverTargetsRequest
13 | import pl.wendigo.chrome.api.target.TargetID
14 | import pl.wendigo.chrome.api.target.TargetInfo
15 | import pl.wendigo.chrome.on
16 | import pl.wendigo.chrome.protocol.ProtocolConnection
17 | import pl.wendigo.chrome.sync
18 | import java.io.Closeable
19 |
20 | /**
21 | * [Manager] is responsible for querying, creating, closing, attaching to debuggable [Target]s on the controlled Chrome instance.
22 | */
23 | class Manager(
24 | private val browserDebuggerAddress: String,
25 | private val multiplexConnections: Boolean,
26 | private val eventsBufferSize: Int,
27 | private val domains: ProtocolDomains
28 | ) : Closeable, AutoCloseable {
29 | private val targets: MutableMap = mutableMapOf()
30 |
31 | /**
32 | * Closes underlying connection to debugger.
33 | */
34 | override fun close() {
35 | domains.close()
36 | }
37 |
38 | init {
39 | on(domains.Target.targetCreated().filter { it.targetInfo.isPage() }) {
40 | targets[it.targetInfo.targetId] = it.targetInfo
41 | logger.debug("Target {} was created", it.targetInfo)
42 | }
43 |
44 | on(domains.Target.targetDestroyed()) {
45 | if (targets.remove(it.targetId) != null) {
46 | logger.debug("Target {} was destroyed", it.targetId)
47 | }
48 | }
49 |
50 | on(domains.Target.targetInfoChanged().filter { it.targetInfo.isPage() }) {
51 | targets[it.targetInfo.targetId] = it.targetInfo
52 | logger.debug("Target {} was changed", it.targetInfo)
53 | }
54 |
55 | on(domains.Target.targetCrashed()) {
56 | if (targets.remove(it.targetId) != null) {
57 | logger.debug("Target {} has crashed", it.targetId)
58 | }
59 | }
60 |
61 | sync(domains.Target.setDiscoverTargets(SetDiscoverTargetsRequest(discover = true)))
62 | }
63 |
64 | /**
65 | * Closes target and destroys browser context if present on the browser side effectively releasing all resources .
66 | *
67 | * If [multiplexConnections] is false, then underlying connection to the [Target]'s debugger is also closed.
68 | */
69 | fun close(target: Target) {
70 | logger.info("Closing {}...", target)
71 |
72 | val browserContextID = target.info().browserContextId
73 |
74 | sync(domains.Target.closeTarget(CloseTargetRequest(target.targetId()))).run {
75 | logger.info("Closed {}", target.session())
76 | }
77 |
78 | if (!browserContextID.isNullOrEmpty()) {
79 | sync(domains.Target.disposeBrowserContext(DisposeBrowserContextRequest(browserContextID))).run {
80 | logger.info("Destroyed browser context {}", browserContextID)
81 | }
82 | }
83 |
84 | if (!multiplexConnections) {
85 | target.closeConnection()
86 | }
87 | }
88 |
89 | /**
90 | * Creates new target with given [url] and viewport [width] and [height].
91 | *
92 | * If [incognito] is true, than new target is created in separate browser context (think of it as incognito window).
93 | */
94 | internal fun create(url: String, incognito: Boolean = true, width: Int = 1024, height: Int = 768): Target {
95 | logger.info("Creating new target [url=$url, incognito=$incognito, viewport=[$width, $height]]")
96 |
97 | val browserContextId = when (incognito) {
98 | true -> sync(domains.Target.createBrowserContext(CreateBrowserContextRequest(disposeOnDetach = true))).browserContextId
99 | false -> null
100 | }
101 |
102 | val (targetId) = sync(
103 | domains.Target.createTarget(
104 | CreateTargetRequest(
105 | url = url,
106 | browserContextId = browserContextId,
107 | height = height,
108 | width = width,
109 | background = true
110 | )
111 | )
112 | )
113 |
114 | val targetInfo = sync(domains.Target.getTargetInfo(GetTargetInfoRequest(targetId = targetId))).targetInfo
115 |
116 | logger.info("Created new target [$targetInfo]")
117 |
118 | return attach(targetInfo)
119 | }
120 |
121 | /**
122 | * Returns list of all debuggable targets on the browser side.
123 | */
124 | fun list(): List {
125 | return targets.values.toList()
126 | }
127 |
128 | /**
129 | * Attaches to given [TargetInfo] and returns new [Target] for it.
130 | *
131 | * If [multiplexConnections] is true then existing debugger browser connection is used: [#991325](https://crbug.com/991325))
132 | * Otherwise new underlying connection to target's debugger endpoint is established.
133 | */
134 | fun attach(target: TargetInfo): Target {
135 | val sessionId = when (multiplexConnections) {
136 | true -> sync(
137 | domains.Target.attachToTarget(
138 | AttachToTargetRequest(
139 | targetId = target.targetId,
140 | flatten = true
141 | )
142 | )
143 | ).sessionId
144 |
145 | false -> ""
146 | }
147 |
148 | return Target(
149 | session = target.toTarget(sessionId),
150 | connection = openConnection(target, sessionId),
151 | manager = this
152 | )
153 | }
154 |
155 | /**
156 | * Constructs target debugger address (if not using multiplexed connections).
157 | */
158 | private fun targetWsAddress(targetID: TargetID): String {
159 | return browserDebuggerAddress.replace(
160 | browserDebuggerAddress.substringAfterLast("devtools"),
161 | "/page/$targetID"
162 | )
163 | }
164 |
165 | private fun openConnection(target: TargetInfo, sessionId: String): ProtocolConnection {
166 | return when (multiplexConnections) {
167 | true -> domains.cloneConnection(sessionId)
168 | false -> ProtocolConnection.open(targetWsAddress(target.targetId), eventsBufferSize)
169 | }
170 | }
171 |
172 | companion object {
173 | private val logger: Logger = LoggerFactory.getLogger(Manager::class.java)
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/main/kotlin/pl/wendigo/chrome/api/audits/Domain.kt:
--------------------------------------------------------------------------------
1 | package pl.wendigo.chrome.api.audits
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | /**
6 | * Audits domain allows investigation of page violations and possible improvements.
7 | *
8 | * This API is marked as experimental in protocol definition and can change in the future.
9 | * @link Protocol [Audits](https://chromedevtools.github.io/devtools-protocol/tot/Audits) domain documentation.
10 | */
11 | @pl.wendigo.chrome.protocol.Experimental
12 | class AuditsDomain internal constructor(connection: pl.wendigo.chrome.protocol.ProtocolConnection) :
13 | pl.wendigo.chrome.protocol.Domain("Audits", """Audits domain allows investigation of page violations and possible improvements.""", connection) {
14 | /**
15 | * Returns the response body and size if it were re-encoded with the specified settings. Only
16 | applies to images.
17 | *
18 | * @link Protocol [Audits#getEncodedResponse](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-getEncodedResponse) method documentation.
19 | */
20 |
21 | fun getEncodedResponse(input: GetEncodedResponseRequest): io.reactivex.rxjava3.core.Single = connection.request("Audits.getEncodedResponse", Json.encodeToJsonElement(GetEncodedResponseRequest.serializer(), input), GetEncodedResponseResponse.serializer())
22 |
23 | /**
24 | * Disables issues domain, prevents further issues from being reported to the client.
25 | *
26 | * @link Protocol [Audits#disable](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-disable) method documentation.
27 | */
28 |
29 | fun disable(): io.reactivex.rxjava3.core.Single = connection.request("Audits.disable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
30 |
31 | /**
32 | * Enables issues domain, sends the issues collected so far to the client by means of the
33 | `issueAdded` event.
34 | *
35 | * @link Protocol [Audits#enable](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-enable) method documentation.
36 | */
37 |
38 | fun enable(): io.reactivex.rxjava3.core.Single = connection.request("Audits.enable", null, pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
39 |
40 | /**
41 | * Runs the contrast check for the target page. Found issues are reported
42 | using Audits.issueAdded event.
43 | *
44 | * @link Protocol [Audits#checkContrast](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-checkContrast) method documentation.
45 | */
46 |
47 | fun checkContrast(input: CheckContrastRequest): io.reactivex.rxjava3.core.Single = connection.request("Audits.checkContrast", Json.encodeToJsonElement(CheckContrastRequest.serializer(), input), pl.wendigo.chrome.protocol.websocket.RequestResponseFrame.serializer())
48 |
49 | /**
50 | * Returns observable capturing all Audits.issueAdded events.
51 | */
52 | fun issueAdded(): io.reactivex.rxjava3.core.Flowable = connection.events("Audits.issueAdded", IssueAddedEvent.serializer())
53 |
54 | /**
55 | * Returns list of dependant domains that should be enabled prior to enabling this domain.
56 | */
57 | override fun getDependencies(): List {
58 | return arrayListOf(
59 | pl.wendigo.chrome.api.network.NetworkDomain(connection),
60 | )
61 | }
62 | }
63 |
64 | /**
65 | * Represents request frame that can be used with [Audits#getEncodedResponse](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-getEncodedResponse) operation call.
66 | *
67 | * Returns the response body and size if it were re-encoded with the specified settings. Only
68 | applies to images.
69 | * @link [Audits#getEncodedResponse](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-getEncodedResponse) method documentation.
70 | * @see [AuditsDomain.getEncodedResponse]
71 | */
72 | @kotlinx.serialization.Serializable
73 | data class GetEncodedResponseRequest(
74 | /**
75 | * Identifier of the network request to get content for.
76 | */
77 | val requestId: pl.wendigo.chrome.api.network.RequestId,
78 |
79 | /**
80 | * The encoding to use.
81 | */
82 | val encoding: String,
83 |
84 | /**
85 | * The quality of the encoding (0-1). (defaults to 1)
86 | */
87 | val quality: Double? = null,
88 |
89 | /**
90 | * Whether to only return the size information (defaults to false).
91 | */
92 | val sizeOnly: Boolean? = null
93 |
94 | )
95 |
96 | /**
97 | * Represents response frame that is returned from [Audits#getEncodedResponse](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-getEncodedResponse) operation call.
98 | * Returns the response body and size if it were re-encoded with the specified settings. Only
99 | applies to images.
100 | *
101 |
102 | * @link [Audits#getEncodedResponse](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-getEncodedResponse) method documentation.
103 | * @see [AuditsDomain.getEncodedResponse]
104 | */
105 | @kotlinx.serialization.Serializable
106 | data class GetEncodedResponseResponse(
107 | /**
108 | * The encoded body as a base64 string. Omitted if sizeOnly is true. (Encoded as a base64 string when passed over JSON)
109 | */
110 | val body: String? = null,
111 |
112 | /**
113 | * Size before re-encoding.
114 | */
115 | val originalSize: Int,
116 |
117 | /**
118 | * Size after re-encoding.
119 | */
120 | val encodedSize: Int
121 |
122 | )
123 |
124 | /**
125 | * Represents request frame that can be used with [Audits#checkContrast](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-checkContrast) operation call.
126 | *
127 | * Runs the contrast check for the target page. Found issues are reported
128 | using Audits.issueAdded event.
129 | * @link [Audits#checkContrast](https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-checkContrast) method documentation.
130 | * @see [AuditsDomain.checkContrast]
131 | */
132 | @kotlinx.serialization.Serializable
133 | data class CheckContrastRequest(
134 | /**
135 | * Whether to report WCAG AAA level issues. Default is false.
136 | */
137 | val reportAAA: Boolean? = null
138 |
139 | )
140 |
141 | /**
142 | *
143 | *
144 | * @link [Audits#issueAdded](https://chromedevtools.github.io/devtools-protocol/tot/Audits#event-issueAdded) event documentation.
145 | */
146 | @kotlinx.serialization.Serializable
147 | data class IssueAddedEvent(
148 | /**
149 | *
150 | */
151 | val issue: InspectorIssue
152 |
153 | ) : pl.wendigo.chrome.protocol.Event {
154 | override fun domain() = "Audits"
155 | override fun eventName() = "issueAdded"
156 | }
157 |
--------------------------------------------------------------------------------