-
-
Save daviddenton/63942d3bafb4c64445ed949bec8819ec to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.http4k.h4k.example.lib | |
import org.http4k.cloudnative.env.Port | |
import org.http4k.core.HttpHandler | |
import org.http4k.server.Http4kServer | |
import org.http4k.server.SunHttp | |
import org.http4k.server.asServer | |
interface Discovery<ServiceId> { | |
fun lookup(id: ServiceId): HttpHandler | |
} | |
class H4KCluster<ServiceId> : Discovery<ServiceId> { | |
private val services = mutableMapOf<ServiceId, HttpHandler>() | |
private val servers = mutableListOf<Pair<ServiceId, Http4kServer>>() | |
override fun lookup(id: ServiceId) = services[id] | |
?: throw IllegalStateException("$id is not registered in this cluster") | |
fun install(id: ServiceId, appFn: (Discovery<ServiceId>) -> HttpHandler) = apply { | |
val app = appFn(this) | |
services[id] = app | |
} | |
fun expose(id: ServiceId, port: Port) = apply { | |
servers += id to lookup(id).asServer(SunHttp(port.value)) | |
} | |
fun start() = apply { | |
servers.forEach { | |
it.second.start() | |
println("Bound ${it.first} to ${it.second.port()}") | |
} | |
} | |
fun stop() = apply { | |
servers.forEach { | |
it.second.stop() | |
println("Unbound ${it.first}") | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.http4k.h4k.example.main | |
import org.http4k.core.HttpHandler | |
import org.http4k.core.Method | |
import org.http4k.core.Request | |
import org.http4k.core.Response | |
import org.http4k.core.Status | |
data class InternalServiceId(val name: String) | |
data class ExternalServiceId(val name: String) | |
/** | |
* Proxies requests to the App service | |
*/ | |
object Proxy { | |
val ID = InternalServiceId("proxy") | |
operator fun invoke(appHttp: HttpHandler) = { req: Request -> appHttp(req) } | |
} | |
/** | |
* This is a particular application which uses the 3rd party Reverser service | |
*/ | |
object App { | |
val ID = InternalServiceId("app") | |
operator fun invoke(reverserHttp: HttpHandler): HttpHandler { | |
val reverser = Reverser.Client(reverserHttp) | |
return { _: Request -> Response(Status.OK).body(reverser.reverse("hello world")) } | |
} | |
} | |
/** | |
* Domain client for the 3rd party Reverser service | |
*/ | |
object Reverser { | |
val ID = ExternalServiceId("reverser") | |
class Client(private val http: HttpHandler) { | |
fun reverse(input: String) = http(Request(Method.GET, "/").body(input)).bodyString() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.http4k.h4k.example.test | |
import org.http4k.client.OkHttp | |
import org.http4k.cloudnative.env.Port | |
import org.http4k.core.HttpHandler | |
import org.http4k.core.Method | |
import org.http4k.core.Request | |
import org.http4k.core.Response | |
import org.http4k.core.Status | |
import org.http4k.core.Uri | |
import org.http4k.core.then | |
import org.http4k.filter.ClientFilters | |
import org.http4k.h4k.example.lib.H4KCluster | |
import org.http4k.h4k.example.main.App | |
import org.http4k.h4k.example.main.ExternalServiceId | |
import org.http4k.h4k.example.main.InternalServiceId | |
import org.http4k.h4k.example.main.Proxy | |
import org.http4k.h4k.example.main.Reverser | |
fun FakeReverserApp(): HttpHandler = { req: Request -> Response(Status.OK).body(req.bodyString().reversed()) } | |
fun main() { | |
// this is our "fakes" cluster | |
val egress = H4KCluster<ExternalServiceId>() | |
.install(Reverser.ID) { FakeReverserApp() } | |
.expose(Reverser.ID, Port(10000)) | |
.start() | |
// this is our service cluster | |
val cluster = H4KCluster<InternalServiceId>() | |
.install(App.ID) { App(egress.lookup(Reverser.ID)) } | |
.install(Proxy.ID) { discovery -> Proxy(discovery.lookup(App.ID)) } | |
.expose(Proxy.ID, Port(8000)) | |
.start() | |
// look up the service HttpHandler by ID | |
println(cluster.lookup(Proxy.ID)(Request(Method.GET, ""))) | |
// because we've exposed it, we can also go over the wire | |
val client = ClientFilters.SetBaseUriFrom(Uri.of("http://localhost:8000")).then(OkHttp()) | |
println(client(Request(Method.GET, ""))) | |
cluster.stop() | |
egress.stop() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment