Skip to content

Commit

Permalink
Http4s builders accept client builder
Browse files Browse the repository at this point in the history
  • Loading branch information
hnaderi committed May 17, 2023
1 parent cb7898d commit 12b4d93
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 117 deletions.
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ import dev.hnaderi.k8s.client.http4s.EmberKubernetesClient
import io.circe.Json
import org.http4s.circe._

val buildClient = EmberKubernetesClient.defaultConfig[IO, Json]
val buildClient = EmberKubernetesClient[IO].defaultConfig[Json]

val getNodes = buildClient.use(APIs.nodes.list().send)

Expand Down
2 changes: 1 addition & 1 deletion examples/cross-platform/src/main/scala/EmberExample.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import org.http4s.circe._

object EmberExample extends IOApp {

private val client = EmberKubernetesClient.defaultConfig[IO, Json]
private val client = EmberKubernetesClient[IO].defaultConfig[Json]

def operations(cl: HttpClient[IO]) = for {
_ <- APIs.namespace("default").configmaps.list.send(cl).flatMap(IO.println)
Expand Down
5 changes: 3 additions & 2 deletions examples/jvm/src/main/scala/Http4sExample.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import cats.implicits._
import dev.hnaderi.k8s.circe._
import dev.hnaderi.k8s.client._
import dev.hnaderi.k8s.client.http4s.EmberKubernetesClient
import dev.hnaderi.k8s.client.http4s.KClient
import dev.hnaderi.k8s.client.implicits._
import dev.hnaderi.k8s.implicits._
import fs2.Stream._
Expand All @@ -31,9 +32,9 @@ import org.http4s.circe._

object Http4sExample extends IOApp {

private val client = EmberKubernetesClient.defaultConfig[IO, Json]
private val client = EmberKubernetesClient[IO].defaultConfig[Json]

def watchNodes(cl: EmberKubernetesClient.KClient[IO]) =
def watchNodes(cl: KClient[IO]) =
CoreV1.nodes
.list()
.listen(cl)
Expand Down
20 changes: 16 additions & 4 deletions modules/http4s-blaze/src/main/scala/BlazeKubernetesClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,30 @@ package http4s

import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.effect.std.Env
import fs2.io.file.Files
import org.http4s.blaze.client.BlazeClientBuilder
import org.http4s.client.Client

import javax.net.ssl.SSLContext

object BlazeKubernetesClient extends Http4sKubernetesClient with JVMPlatform {
final class BlazeKubernetesClient[F[_]: Async: Files: Env] private (
builder: BlazeClientBuilder[F]
) extends JVMPlatform[F] {

override protected def buildClient[F[_]: Async]: Resource[F, Client[F]] =
override protected def buildClient: Resource[F, Client[F]] =
BlazeClientBuilder[F].resource

override protected def buildWithSSLContext[F[_]: Async]
override protected def buildWithSSLContext
: SSLContext => Resource[F, Client[F]] =
BlazeClientBuilder[F].withSslContext(_).resource
builder.withSslContext(_).resource

}

object BlazeKubernetesClient {
def apply[F[_]: Async: Files: Env]: BlazeKubernetesClient[F] =
new BlazeKubernetesClient(BlazeClientBuilder[F])
def apply[F[_]: Async: Files: Env](
builder: BlazeClientBuilder[F]
): BlazeKubernetesClient[F] = new BlazeKubernetesClient(builder)
}
51 changes: 25 additions & 26 deletions modules/http4s-ember/.js/src/main/scala/PlatformCompanion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
*/

package dev.hnaderi.k8s.client
package http4s

import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.syntax.all._
import dev.hnaderi.k8s.client.http4s.EmberKubernetesClient
import dev.hnaderi.k8s.utils._
import fs2.Chunk
import fs2.Stream
Expand All @@ -29,37 +29,40 @@ import fs2.io.net.tls.SecureContext
import fs2.io.net.tls.TLSContext
import org.http4s._
import scodec.bits.ByteVector
import cats.effect.std.Env

private[client] trait PlatformCompanion extends Http4sKubernetesClient {
self: EmberKubernetesClient =>
private[http4s] abstract class PlatformCompanion[F[_]: Async: Files: Env]
extends Http4sKubernetesClient[F] {
self: EmberKubernetesClient[F] =>

private def ssl[F[_]: Async: Files](
private def ssl(
caData: Option[String] = None,
caFile: Option[String],
clientCert: Option[String] = None,
clientCertFile: Option[String],
clientKey: Option[String] = None,
clientKeyFile: Option[String],
clientKeyPass: Option[String] = None
): Resource[F, TLSContext[F]] = Resource.eval(
for {
ca <- dataOrFile(caData, caFile)
cert <- dataOrFile(clientCert, clientCertFile)
key <- dataOrFile(clientKey, clientKeyFile)
} yield TLSContext.Builder
.forAsync[F]
.fromSecureContext(
SecureContext(
ca = ca.map(v => Seq(Left(v))),
cert = cert.map(v => Seq(Left(v))),
key = key.map(ck =>
Seq(SecureContext.Key(Left(ck), passphrase = clientKeyPass))
): Resource[F, TLSContext[F]] =
Resource.eval(
for {
ca <- dataOrFile(caData, caFile)
cert <- dataOrFile(clientCert, clientCertFile)
key <- dataOrFile(clientKey, clientKeyFile)
} yield TLSContext.Builder
.forAsync[F]
.fromSecureContext(
SecureContext(
ca = ca.map(v => Seq(Left(v))),
cert = cert.map(v => Seq(Left(v))),
key = key.map(ck =>
Seq(SecureContext.Key(Left(ck), passphrase = clientKeyPass))
)
)
)
)
)
)

private def dataOrFile[F[_]: Async: Files](
private def dataOrFile(
data: Option[String],
file: Option[String]
): F[Option[Chunk[Byte]]] = {
Expand All @@ -74,12 +77,10 @@ private[client] trait PlatformCompanion extends Http4sKubernetesClient {
.map(base64Data(_))
}

final override def fromConfig[F[_], T](
final override def fromConfig[T](
config: Config,
context: Option[String] = None
)(implicit
F: Async[F],
Files: Files[F],
enc: EntityEncoder[F, T],
dec: EntityDecoder[F, T],
builder: Builder[T],
Expand Down Expand Up @@ -114,16 +115,14 @@ private[client] trait PlatformCompanion extends Http4sKubernetesClient {

}

final override def from[F[_], T](
final override def from[T](
server: String,
ca: Option[Path] = None,
clientCert: Option[Path] = None,
clientKey: Option[Path] = None,
clientKeyPassword: Option[String] = None,
authentication: AuthenticationParams = AuthenticationParams.empty
)(implicit
F: Async[F],
Files: Files[F],
enc: EntityEncoder[F, T],
dec: EntityDecoder[F, T],
builder: Builder[T],
Expand Down
11 changes: 7 additions & 4 deletions modules/http4s-ember/.jvm/src/main/scala/PlatformCompanion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,22 @@
*/

package dev.hnaderi.k8s.client
package http4s

import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import dev.hnaderi.k8s.client.http4s.EmberKubernetesClient
import fs2.io.net.tls.TLSContext
import org.http4s.client.Client
import cats.effect.std.Env

import javax.net.ssl.SSLContext
import fs2.io.file.Files

private[client] trait PlatformCompanion extends JVMPlatform {
self: EmberKubernetesClient with Http4sKubernetesClient =>
private[http4s] abstract class PlatformCompanion[F[_]: Async: Files: Env]
extends JVMPlatform[F] {
self: EmberKubernetesClient[F] =>

override protected def buildWithSSLContext[F[_]: Async]
override protected def buildWithSSLContext
: SSLContext => Resource[F, Client[F]] = ctx =>
buildSecureClient(TLSContext.Builder.forAsync[F].fromSSLContext(ctx))
}
23 changes: 11 additions & 12 deletions modules/http4s-ember/.native/src/main/scala/PlatformCompanion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
*/

package dev.hnaderi.k8s.client
package http4s

import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.syntax.all._
import dev.hnaderi.k8s.client.http4s.EmberKubernetesClient
import dev.hnaderi.k8s.utils._
import fs2.Stream
import fs2.io.file.Files
Expand All @@ -30,10 +30,13 @@ import fs2.io.net.tls.TLSContext
import org.http4s._
import org.http4s.client.Client
import scodec.bits.ByteVector
import cats.effect.std.Env

private[client] trait PlatformCompanion extends Http4sKubernetesClient {
self: EmberKubernetesClient =>
private def dataOrFile[F[_]: Async: Files](
private[http4s] abstract class PlatformCompanion[F[_]: Async: Files: Env]
extends Http4sKubernetesClient[F] {
self: EmberKubernetesClient[F] =>

private def dataOrFile(
data: Option[String],
file: Option[String]
): Resource[F, Option[ByteVector]] =
Expand All @@ -45,7 +48,7 @@ private[client] trait PlatformCompanion extends Http4sKubernetesClient {
.getOrElse(Option.empty.pure)
)

private def client[F[_]: Async: Files](
private def client(
caData: Option[String] = None,
caFile: Option[String],
clientCert: Option[String] = None,
Expand All @@ -67,12 +70,10 @@ private[client] trait PlatformCompanion extends Http4sKubernetesClient {
client <- buildSecureClient(tls)
} yield client

final override def fromConfig[F[_], T](
final override def fromConfig[T](
config: Config,
context: Option[String] = None
)(implicit
F: Async[F],
Files: Files[F],
enc: EntityEncoder[F, T],
dec: EntityDecoder[F, T],
builder: Builder[T],
Expand All @@ -93,7 +94,7 @@ private[client] trait PlatformCompanion extends Http4sKubernetesClient {
).raiseError
)
case Some((cluster, server, auth)) =>
client[F](
client(
caFile = cluster.`certificate-authority`,
caData = cluster.`certificate-authority-data`,
clientCert = auth.`client-certificate-data`,
Expand All @@ -107,16 +108,14 @@ private[client] trait PlatformCompanion extends Http4sKubernetesClient {

}

final override def from[F[_], T](
final override def from[T](
server: String,
ca: Option[Path] = None,
clientCert: Option[Path] = None,
clientKey: Option[Path] = None,
clientKeyPassword: Option[String] = None,
authentication: AuthenticationParams = AuthenticationParams.empty
)(implicit
F: Async[F],
Files: Files[F],
enc: EntityEncoder[F, T],
dec: EntityDecoder[F, T],
builder: Builder[T],
Expand Down
29 changes: 17 additions & 12 deletions modules/http4s-ember/src/main/scala/EmberKubernetesClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,28 @@ import fs2.io.net.Network
import fs2.io.net.tls.TLSContext
import org.http4s.client.Client
import org.http4s.ember.client.EmberClientBuilder
import fs2.io.file.Files
import cats.effect.std.Env

object EmberKubernetesClient extends EmberKubernetesClient

trait EmberKubernetesClient extends PlatformCompanion {

override protected def buildClient[F[_]: Async]: Resource[F, Client[F]] = {
implicit val net: Network[F] = Network.forAsync[F]
final class EmberKubernetesClient[F[_]: Async: Network: Files: Env] private (
builder: EmberClientBuilder[F]
) extends PlatformCompanion[F] {

override protected def buildClient: Resource[F, Client[F]] =
EmberClientBuilder.default[F].build
}

protected def buildSecureClient[F[_]: Async](
protected def buildSecureClient(
ctx: TLSContext[F]
): Resource[F, Client[F]] = {
implicit val net: Network[F] = Network.forAsync[F]
): Resource[F, Client[F]] = builder.withTLSContext(ctx).build

}

EmberClientBuilder.default[F].withTLSContext(ctx).build
}
object EmberKubernetesClient {
def apply[F[_]: Async: Network: Files: Env]: EmberKubernetesClient[F] =
new EmberKubernetesClient[F](EmberClientBuilder.default[F])

def apply[F[_]: Async: Network: Files: Env](
builder: EmberClientBuilder[F]
): EmberKubernetesClient[F] =
new EmberKubernetesClient[F](builder)
}
16 changes: 9 additions & 7 deletions modules/http4s-jdk/src/main/scala/JDKKubernetesClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ import org.http4s.jdkhttpclient.JdkHttpClient

import java.net.http
import javax.net.ssl.SSLContext
import cats.effect.std.Env
import fs2.io.file.Files

object JDKKubernetesClient extends Http4sKubernetesClient with JVMPlatform {
final class JDKKubernetesClient[F[_]: Async: Files: Env]
extends JVMPlatform[F] {

override protected def buildClient[F[_]: Async]: Resource[F, Client[F]] =
override protected def buildClient: Resource[F, Client[F]] =
Resource.eval(JdkHttpClient.simple[F])

override protected def buildWithSSLContext[F[_]](implicit
F: Async[F]
): SSLContext => Resource[F, Client[F]] = ssl =>
Resource.eval(F.executor.flatMap { exec =>
F.delay {
override protected def buildWithSSLContext
: SSLContext => Resource[F, Client[F]] = ssl =>
Resource.eval(Async[F].executor.flatMap { exec =>
Async[F].delay {
val builder = http.HttpClient.newBuilder()
// workaround for https://github.com/http4s/http4s-jdk-http-client/issues/200
if (Runtime.version().feature() == 11) {
Expand Down
20 changes: 16 additions & 4 deletions modules/http4s-netty/src/main/scala/NettyKubernetesClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,30 @@ package http4s

import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.effect.std.Env
import fs2.io.file.Files
import org.http4s.client.Client
import org.http4s.netty.client.NettyClientBuilder

import javax.net.ssl.SSLContext

object NettyKubernetesClient extends Http4sKubernetesClient with JVMPlatform {
final class NettyKubernetesClient[F[_]: Async: Files: Env] private (
builder: NettyClientBuilder[F]
) extends JVMPlatform[F] {

override protected def buildClient[F[_]: Async]: Resource[F, Client[F]] =
override protected def buildClient: Resource[F, Client[F]] =
NettyClientBuilder[F].resource

override protected def buildWithSSLContext[F[_]: Async]
override protected def buildWithSSLContext
: SSLContext => Resource[F, Client[F]] =
NettyClientBuilder[F].withSSLContext(_).resource
builder.withSSLContext(_).resource

}

object NettyKubernetesClient {
def apply[F[_]: Async: Files: Env]: NettyKubernetesClient[F] =
new NettyKubernetesClient(NettyClientBuilder[F])
def apply[F[_]: Async: Files: Env](
builder: NettyClientBuilder[F]
): NettyKubernetesClient[F] = new NettyKubernetesClient(builder)
}
Loading

0 comments on commit 12b4d93

Please sign in to comment.