All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.malliina.http.OkClient.scala Maven / Gradle / Ivy

There is a newer version: 3.7.3
Show newest version
package com.malliina.http

import java.io.{Closeable, IOException}
import java.nio.file.Path
import java.util
import java.util.concurrent.Executors

import javax.net.ssl.{SSLSocketFactory, X509TrustManager}
import okhttp3._

import scala.concurrent.{ExecutionContext, Future, Promise}

object OkClient {
  val jsonMediaType: MediaType = MediaType.parse("application/json")
  val plainText = MediaType.parse("text/plain")

  def default: OkClient = apply(okHttpClient)

  def ssl(ssf: SSLSocketFactory, tm: X509TrustManager): OkClient =
    apply(sslClient(ssf, tm))

  def apply(client: OkHttpClient = okHttpClient): OkClient =
    new OkClient(client, defaultExecutionContext())

  def okHttpClient: OkHttpClient =
    new OkHttpClient.Builder()
      .protocols(util.Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
      .build()

  def sslClient(ssf: SSLSocketFactory, tm: X509TrustManager): OkHttpClient =
    new OkHttpClient.Builder()
      .sslSocketFactory(ssf, tm)
      .protocols(util.Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
      .build()

  def defaultExecutionContext() =
    ExecutionContext.fromExecutorService(Executors.newCachedThreadPool())

  case class MultiPartFile(partName: String, fileName: String, mediaType: MediaType, file: Path)

  object MultiPartFile {
    def apply(mediaType: MediaType, file: Path): MultiPartFile =
      MultiPartFile("file", file.getFileName.toString, mediaType, file)
  }
}

class OkClient(val client: OkHttpClient, ec: ExecutionContext)
  extends HttpClient[Future]
  with OkHttpBackend {
  implicit val exec: ExecutionContext = ec

  def execute(request: Request): Future[OkHttpResponse] =
    raw(request).map(OkHttpResponse.apply)

  /** Provides the response but closes the response body after `consume` completes.
    *
    * @param request request
    * @param consume code to consume the response
    * @tparam T type of result
    * @return
    */
  def streamed[T](request: Request)(consume: Response => Future[T]): Future[T] = {
    raw(request).flatMap { r =>
      val work = consume(r)
      work.onComplete(_ => r.close())
      work
    }
  }

  /** Remember to close the response body if calling this method. If you don't need to stream the response,
    * call `execute` instead.
    *
    * @param request request to execute
    * @return the response
    */
  def raw(request: Request): Future[Response] = {
    val (future, callback) = RawCallback.paired()
    client.newCall(request).enqueue(callback)
    future
  }

  override def flatMap[T, U](t: Future[T])(f: T => Future[U]): Future[U] = t.flatMap(f)
  override def success[T](t: T): Future[T] = Future.successful(t)
  override def fail[T](e: Exception): Future[T] = Future.failed(e)
}

class RawCallback(p: Promise[Response]) extends Callback {
  override def onFailure(call: Call, e: IOException): Unit =
    p.tryFailure(e)

  override def onResponse(call: Call, response: Response): Unit =
    p.trySuccess(response)
}

object RawCallback {
  def paired() = {
    val p = Promise[Response]()
    val callback = new RawCallback(p)
    (p.future, callback)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy