diff options
5 files changed, 75 insertions, 8 deletions
@@ -243,16 +243,21 @@ To use, add the following dependency to your project: "com.softwaremill.sttp" %% "async-http-client-handler-future" % version // or "com.softwaremill.sttp" %% "async-http-client-handler-scalaz" % version +// or +"com.softwaremill.sttp" %% "async-http-client-handler-monix" % version ``` This handler depends on [async-http-handler](https://github.com/AsyncHttpClient/async-http-client). A fully **asynchronous** handler, which uses [Netty](http://netty.io) behind the scenes. -The responses are either wrapped in a `Future`, or a -[Scalaz](https://github.com/scalaz/scalaz) `Task`, depending on the -dependency chosen. In the latter case, there's an additional transitive +The responses are wrapped depending on the dependency chosen in either a: + +* standard Scala `Future` +* [Scalaz](https://github.com/scalaz/scalaz) `Task`. There's a transitive dependency on `scalaz-concurrent`. +* [Monix](https://monix.io) `Task`. There's a transitive dependency on +`monix-eval`. Next you'll need to add an implicit value: @@ -262,6 +267,9 @@ implicit val sttpHandler = new FutureAsyncHttpClientHandler() // or, if you're using the scalaz version: implicit val sttpHandler = new ScalazAsyncHttpClientHandler() +// or, if you're using the monix version: +implicit val sttpHandler = new MonixAsyncHttpClientHandler() + // or, if you'd like to use custom configuration: implicit val sttpHandler = new FutureAsyncHttpClientHandler(asyncHttpClientConfig) diff --git a/async-http-client-handler/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/MonixAsyncHttpClientHandler.scala b/async-http-client-handler/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/MonixAsyncHttpClientHandler.scala new file mode 100644 index 0000000..ddfacb5 --- /dev/null +++ b/async-http-client-handler/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/MonixAsyncHttpClientHandler.scala @@ -0,0 +1,35 @@ +package com.softwaremill.sttp.asynchttpclient.monix + +import com.softwaremill.sttp.asynchttpclient.internal.{ + AsyncHttpClientHandler, + WrapperFromAsync +} +import monix.eval.Task +import monix.execution.Cancelable +import org.asynchttpclient.{ + AsyncHttpClient, + AsyncHttpClientConfig, + DefaultAsyncHttpClient +} + +import scala.util.{Failure, Success} + +class MonixAsyncHttpClientHandler(asyncHttpClient: AsyncHttpClient) + extends AsyncHttpClientHandler[Task](asyncHttpClient, TaskFromAsync) { + + def this() = this(new DefaultAsyncHttpClient()) + def this(cfg: AsyncHttpClientConfig) = this(new DefaultAsyncHttpClient(cfg)) +} + +private[asynchttpclient] object TaskFromAsync extends WrapperFromAsync[Task] { + override def apply[T]( + register: ((Either[Throwable, T]) => Unit) => Unit): Task[T] = + Task.async { (_, cb) => + register { + case Left(t) => cb(Failure(t)) + case Right(t) => cb(Success(t)) + } + + Cancelable.empty + } +} @@ -47,7 +47,12 @@ val scalaTest = "org.scalatest" %% "scalatest" % "3.0.3" lazy val rootProject = (project in file(".")) .settings(commonSettings: _*) .settings(publishArtifact := false, name := "sttp") - .aggregate(core, akkaHttpHandler, tests) + .aggregate(core, + akkaHttpHandler, + futureAsyncHttpClientHandler, + scalazAsyncHttpClientHandler, + monixAsyncHttpClientHandler, + tests) lazy val core: Project = (project in file("core")) .settings(commonSettings: _*) @@ -95,6 +100,16 @@ lazy val scalazAsyncHttpClientHandler: Project = (project in file( ) ) dependsOn asyncHttpClientHandler +lazy val monixAsyncHttpClientHandler: Project = (project in file( + "async-http-client-handler/monix")) + .settings(commonSettings: _*) + .settings( + name := "async-http-client-handler-monix", + libraryDependencies ++= Seq( + "io.monix" %% "monix" % "2.3.0" + ) + ) dependsOn asyncHttpClientHandler + lazy val tests: Project = (project in file("tests")) .settings(commonSettings: _*) .settings( @@ -108,4 +123,5 @@ lazy val tests: Project = (project in file("tests")) "ch.qos.logback" % "logback-classic" % "1.2.3" ).map(_ % "test"), libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value % "test" - ) dependsOn (core, akkaHttpHandler, futureAsyncHttpClientHandler, scalazAsyncHttpClientHandler) + ) dependsOn (core, akkaHttpHandler, futureAsyncHttpClientHandler, scalazAsyncHttpClientHandler, +monixAsyncHttpClientHandler) diff --git a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala index f456fb1..030f90c 100644 --- a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala +++ b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala @@ -17,6 +17,7 @@ import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures} import org.scalatest.{BeforeAndAfterAll, FlatSpec, Matchers} import better.files._ import com.softwaremill.sttp.asynchttpclient.future.FutureAsyncHttpClientHandler +import com.softwaremill.sttp.asynchttpclient.monix.MonixAsyncHttpClientHandler import com.softwaremill.sttp.asynchttpclient.scalaz.ScalazAsyncHttpClientHandler import scala.language.higherKinds @@ -122,6 +123,8 @@ class BasicTests ForceWrappedValue.future) runTests("Async Http Client - Scalaz")(new ScalazAsyncHttpClientHandler(), ForceWrappedValue.scalazTask) + runTests("Async Http Client - Monix")(new MonixAsyncHttpClientHandler(), + ForceWrappedValue.monixTask) def runTests[R[_]](name: String)( implicit handler: SttpHandler[R, Nothing], diff --git a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala index 9114d8b..9bf68bb 100644 --- a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala +++ b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala @@ -9,7 +9,6 @@ import org.scalatest.concurrent.ScalaFutures import scala.concurrent.Future import scala.language.higherKinds -import scalaz.concurrent.Task trait TestHttpServer extends BeforeAndAfterAll with ScalaFutures { this: Suite => @@ -44,10 +43,16 @@ trait ForceWrapped extends ScalaFutures { this: Suite => override def force[T](wrapped: Future[T]): T = wrapped.futureValue } - val scalazTask = new ForceWrappedValue[Task] { - override def force[T](wrapped: Task[T]): T = + val scalazTask = new ForceWrappedValue[scalaz.concurrent.Task] { + override def force[T](wrapped: scalaz.concurrent.Task[T]): T = wrapped.unsafePerformSync } + val monixTask = new ForceWrappedValue[monix.eval.Task] { + import monix.execution.Scheduler.Implicits.global + + override def force[T](wrapped: monix.eval.Task[T]): T = + wrapped.runAsync.futureValue + } } implicit class ForceDecorator[R[_], T](wrapped: R[T]) { def force()(implicit fwv: ForceWrappedValue[R]): T = fwv.force(wrapped) |