Skip to content

Commit

Permalink
Future-proofing
Browse files Browse the repository at this point in the history
  • Loading branch information
adamw committed Jan 20, 2025
1 parent caf721b commit 373a803
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import sttp.attributes.AttributeKey
* All of the methods should be non-blocking and complete as fast as possible, so as not to obstruct sending data over
* the network.
*
* To register a callback, set the [[RequestBodyProgressCallback.Attribute]] on a request, using the
* To register a callback, set the [[BodyProgressCallback.RequestAttribute]] on a request, using the
* [[sttp.client4.Request.attribute]] method.
*/
trait RequestBodyProgressCallback {
trait BodyProgressCallback {
def onInit(contentLength: Option[Long]): Unit

def onNext(bytesCount: Long): Unit
Expand All @@ -23,10 +23,10 @@ trait RequestBodyProgressCallback {
def onError(t: Throwable): Unit
}

object RequestBodyProgressCallback {
object BodyProgressCallback {

/** The key of the attribute that should be set on a request, to receive callbacks on the progress of sending the
* request body.
*/
val Attribute = AttributeKey[RequestBodyProgressCallback]
val RequestAttribute = new AttributeKey[BodyProgressCallback](classOf[BodyProgressCallback].getName() + "_request")
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
package sttp.client4.internal.httpclient

import sttp.capabilities.Streams
import sttp.client4.internal.SttpToJavaConverters.toJavaSupplier
import sttp.client4.internal.{throwNestedMultipartNotAllowed, Utf8}
import sttp.client4.compression.Compressor
import sttp.client4._
import sttp.model.{Header, HeaderNames, Part}
import sttp.client4.compression.Compressor
import sttp.client4.httpclient.BodyProgressCallback
import sttp.client4.internal.SttpToJavaConverters.toJavaSupplier
import sttp.client4.internal.Utf8
import sttp.client4.internal.throwNestedMultipartNotAllowed
import sttp.model.Header
import sttp.model.HeaderNames
import sttp.model.Part
import sttp.monad.MonadError
import sttp.monad.syntax._

import java.io.{ByteArrayInputStream, InputStream}
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.net.http.HttpRequest
import java.net.http.HttpRequest.{BodyPublisher, BodyPublishers}
import java.nio.{Buffer, ByteBuffer}
import java.net.http.HttpRequest.BodyPublisher
import java.net.http.HttpRequest.BodyPublishers
import java.nio.Buffer
import java.nio.ByteBuffer
import java.util.concurrent.Flow
import java.util.concurrent.Flow.Subscription
import java.util.function.Supplier
import scala.collection.JavaConverters._
import java.util.concurrent.Flow.Subscription
import sttp.client4.httpclient.RequestBodyProgressCallback

private[client4] trait BodyToHttpClient[F[_], S, R] {
val streams: Streams[S]
Expand Down Expand Up @@ -51,7 +57,7 @@ private[client4] trait BodyToHttpClient[F[_], S, R] {
case Some(cl) => body.map(b => withKnownContentLength(b, cl))
}

request.attribute(RequestBodyProgressCallback.Attribute) match {
request.attribute(BodyProgressCallback.RequestAttribute) match {
case None => bodyWithContentLength
case Some(callback) => bodyWithContentLength.map(withCallback(_, callback))
}
Expand Down Expand Up @@ -99,7 +105,7 @@ private[client4] trait BodyToHttpClient[F[_], S, R] {

private def withCallback(
delegate: HttpRequest.BodyPublisher,
callback: RequestBodyProgressCallback
callback: BodyProgressCallback
): HttpRequest.BodyPublisher =
new HttpRequest.BodyPublisher {
override def contentLength(): Long = delegate.contentLength()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package sttp.client4

import sttp.client4.httpclient.HttpClientSyncBackend
import sttp.client4.httpclient.RequestBodyProgressCallback
import sttp.client4.httpclient.BodyProgressCallback
import sttp.client4.testing.ConvertToFuture
import sttp.client4.testing.HttpTest
import sttp.model.StatusCode
Expand All @@ -23,7 +23,7 @@ class HttpClientSyncHttpTest extends HttpTest[Identity] {
"callback" - {
"should be invoked as described in the callback protocol" in {
val trail = new ConcurrentLinkedQueue[String]()
val callback = new RequestBodyProgressCallback {
val callback = new BodyProgressCallback {

override def onInit(contentLength: Option[Long]): Unit = {
val _ = trail.add(s"init ${contentLength.getOrElse(-1)}")
Expand All @@ -43,7 +43,7 @@ class HttpClientSyncHttpTest extends HttpTest[Identity] {
}

val contentLength = 2048 * 100
val req = postEcho.body("x" * contentLength).attribute(RequestBodyProgressCallback.Attribute, callback)
val req = postEcho.body("x" * contentLength).attribute(BodyProgressCallback.RequestAttribute, callback)

(req.send(backend): Identity[Response[Either[String, String]]]).toFuture().map { response =>
val t = trail.asScala
Expand Down
14 changes: 7 additions & 7 deletions docs/other/body_callbacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ JVM), it is possible to register a callback that keeps track of the progress of

This feature is not available in other backends, and setting the attribute described below will have no effect.

The callback is defined through an instance of the `RequestBodyProgressCallback` trait.
The callback is defined through an instance of the `BodyProgressCallback` trait.

When a request is sent, the `RequestBodyProgressCallback.onInit` method is invoked exactly once with the content length (if it
When a request is sent, the `BodyProgressCallback.onInit` method is invoked exactly once with the content length (if it
is known). This is followed by arbitrary number of `onNext` calls. Finally, either `onComplete` or `onError` are called
exactly once.

Expand All @@ -16,20 +16,20 @@ exactly once.
being transferred.
```

All of the methods in the `RequestBodyProgressCallback` implementation should be non-blocking and complete as fast as possible,
All of the methods in the `BodyProgressCallback` implementation should be non-blocking and complete as fast as possible,
so as not to obstruct sending data over the network.

To register a callback, set the `RequestBodyProgressCallback.Attribute` on a request. For example:
To register a callback, set the `BodyProgressCallback.RequestAttribute` on a request. For example:

```scala mdoc:compile-only
import sttp.client4.*
import sttp.client4.httpclient.{HttpClientSyncBackend, RequestBodyProgressCallback}
import sttp.client4.httpclient.{HttpClientSyncBackend, BodyProgressCallback}
import java.io.File

val backend = HttpClientSyncBackend()

val fileToSend: File = ???
val callback = new RequestBodyProgressCallback {
val callback = new BodyProgressCallback {
override def onInit(contentLength: Option[Long]): Unit = println(s"expected content length: $contentLength")
override def onNext(bytesCount: Long): Unit = println(s"next, bytes: $bytesCount")
override def onComplete(): Unit = println(s"complete")
Expand All @@ -39,6 +39,6 @@ val callback = new RequestBodyProgressCallback {
val response = basicRequest
.get(uri"http://example.com")
.body(fileToSend)
.attribute(RequestBodyProgressCallback.Attribute, callback)
.attribute(BodyProgressCallback.RequestAttribute, callback)
.send(backend)
```

0 comments on commit 373a803

Please sign in to comment.