Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changes/cfc58da7-d2c6-47d7-a40e-72893b49bca7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "cfc58da7-d2c6-47d7-a40e-72893b49bca7",
"type": "feature",
"description": "Enable access to metrics for HTTP streams",
"issues": [
"https://github.com/awslabs/smithy-kotlin/issues/893"
]
}
2 changes: 2 additions & 0 deletions aws-crt-kotlin/api/android/aws-crt-kotlin.api
Original file line number Diff line number Diff line change
Expand Up @@ -635,13 +635,15 @@ public abstract interface class aws/sdk/kotlin/crt/http/HttpStream : aws/sdk/kot
}

public abstract interface class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler {
public abstract fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public abstract fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public abstract fun onResponseComplete (Laws/sdk/kotlin/crt/http/HttpStream;I)V
public abstract fun onResponseHeaders (Laws/sdk/kotlin/crt/http/HttpStream;IILjava/util/List;)V
public abstract fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStream;I)V
}

public final class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler$DefaultImpls {
public static fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public static fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public static fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;I)V
}
Expand Down
2 changes: 2 additions & 0 deletions aws-crt-kotlin/api/jvm/aws-crt-kotlin.api
Original file line number Diff line number Diff line change
Expand Up @@ -635,13 +635,15 @@ public abstract interface class aws/sdk/kotlin/crt/http/HttpStream : aws/sdk/kot
}

public abstract interface class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler {
public abstract fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public abstract fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public abstract fun onResponseComplete (Laws/sdk/kotlin/crt/http/HttpStream;I)V
public abstract fun onResponseHeaders (Laws/sdk/kotlin/crt/http/HttpStream;IILjava/util/List;)V
public abstract fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStream;I)V
}

public final class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler$DefaultImpls {
public static fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public static fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public static fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;I)V
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package aws.sdk.kotlin.crt.http

public data class HttpStreamMetrics(
val sendStartTimestampNs: Long,
val sendEndTimestampNs: Long,
val sendingDurationNs: Long,
val receiveStartTimestampNs: Long,
val receiveEndTimestampNs: Long,
val receivingDurationNs: Long,
val streamId: Int,
)
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ public interface HttpStreamResponseHandler {
// window size through `Stream.incrementWindow()`?
bodyBytesIn.len

/**
* Called right before stream is complete, whether successful or unsuccessful.
* @param stream The HTTP stream to which the metrics apply
* @param metrics The [HttpStreamMetrics] containing metrics for the given stream
*/
public fun onMetrics(stream: HttpStream, metrics: HttpStreamMetrics) {
/* Optional callback, nothing to do by default */
}

/**
* Called from Native when the Response has completed.
* @param stream completed stream
Expand Down
29 changes: 18 additions & 11 deletions aws-crt-kotlin/jvm/src/aws/sdk/kotlin/crt/http/HttpRequestUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,63 @@ package aws.sdk.kotlin.crt.http
import aws.sdk.kotlin.crt.io.MutableBuffer
import aws.sdk.kotlin.crt.io.byteArrayBuffer
import java.nio.ByteBuffer
import software.amazon.awssdk.crt.http.HttpHeader as HttpHeaderJni
import software.amazon.awssdk.crt.http.HttpRequest as HttpRequestJni
import software.amazon.awssdk.crt.http.HttpRequestBodyStream as HttpRequestBodyStreamJni
import software.amazon.awssdk.crt.http.HttpStream as HttpStreamJni
import software.amazon.awssdk.crt.http.HttpStreamMetrics as HttpStreamMetricsJni
import software.amazon.awssdk.crt.http.HttpStreamResponseHandler as HttpStreamResponseHandlerJni

/**
* Convert the KMP version of [HttpRequest] into the JNI equivalent
*/
internal fun HttpRequest.into(): HttpRequestJni {
val jniHeaders = headers.entries()
.map { entry ->
entry.value.map {
software.amazon.awssdk.crt.http.HttpHeader(entry.key, it)
}
entry.value.map { HttpHeaderJni(entry.key, it) }
}
.flatten()
.toTypedArray()

val bodyStream = body?.let { JniRequestBodyStream(it) }
return software.amazon.awssdk.crt.http.HttpRequest(method, encodedPath, jniHeaders, bodyStream)
return HttpRequestJni(method, encodedPath, jniHeaders, bodyStream)
}

internal fun HttpStreamResponseHandler.asJniStreamResponseHandler(): software.amazon.awssdk.crt.http.HttpStreamResponseHandler {
internal fun HttpStreamResponseHandler.asJniStreamResponseHandler(): HttpStreamResponseHandlerJni {
val handler = this
return object : software.amazon.awssdk.crt.http.HttpStreamResponseHandler {
return object : HttpStreamResponseHandlerJni {
override fun onResponseHeaders(
stream: software.amazon.awssdk.crt.http.HttpStream,
stream: HttpStreamJni,
statusCode: Int,
blockType: Int,
headers: Array<out software.amazon.awssdk.crt.http.HttpHeader>?,
headers: Array<out HttpHeaderJni>?,
) {
val ktHeaders = headers?.map { HttpHeader(it.name, it.value) }
val ktStream = HttpStreamJVM(stream)
handler.onResponseHeaders(ktStream, statusCode, blockType, ktHeaders)
}

override fun onResponseHeadersDone(stream: software.amazon.awssdk.crt.http.HttpStream, blockType: Int) {
override fun onResponseHeadersDone(stream: HttpStreamJni, blockType: Int) {
val ktStream = HttpStreamJVM(stream)
handler.onResponseHeadersDone(ktStream, blockType)
}

override fun onResponseBody(stream: software.amazon.awssdk.crt.http.HttpStream, bodyBytesIn: ByteArray?): Int {
override fun onResponseBody(stream: HttpStreamJni, bodyBytesIn: ByteArray?): Int {
if (bodyBytesIn == null) return 0
val ktStream = HttpStreamJVM(stream)
val buffer = byteArrayBuffer(bodyBytesIn)
return handler.onResponseBody(ktStream, buffer)
}

override fun onResponseComplete(stream: software.amazon.awssdk.crt.http.HttpStream, errorCode: Int) {
override fun onResponseComplete(stream: HttpStreamJni, errorCode: Int) {
val ktStream = HttpStreamJVM(stream)
handler.onResponseComplete(ktStream, errorCode)
}

override fun onMetrics(stream: HttpStreamJni, metrics: HttpStreamMetricsJni) {
val ktStream = HttpStreamJVM(stream)
handler.onMetrics(ktStream, metrics.toKotlin())
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package aws.sdk.kotlin.crt.http

/**
* Convert a CRT JNI metrics object into a Kotlin-native one
*/
public fun software.amazon.awssdk.crt.http.HttpStreamMetrics.toKotlin(): HttpStreamMetrics =
HttpStreamMetrics(
sendStartTimestampNs = this.sendStartTimestampNs,
sendEndTimestampNs = this.sendEndTimestampNs,
sendingDurationNs = this.sendingDurationNs,
receiveStartTimestampNs = this.receiveStartTimestampNs,
receiveEndTimestampNs = this.receiveEndTimestampNs,
receivingDurationNs = this.receivingDurationNs,
streamId = this.streamId,
)
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
buildscript {
repositories {
mavenCentral()
mavenLocal()
}

dependencies {
Expand Down