!htp simplify implicit resolution by getting rid of RoutingSetup
This commit is contained in:
parent
3b7d308545
commit
e22118acd7
6 changed files with 87 additions and 98 deletions
|
|
@ -6,12 +6,12 @@ package akka.http.scaladsl.testkit
|
|||
|
||||
import com.typesafe.config.{ ConfigFactory, Config }
|
||||
import scala.collection.immutable
|
||||
import scala.concurrent.{ Await, Future }
|
||||
import scala.concurrent.{ ExecutionContext, Await, Future }
|
||||
import scala.concurrent.duration._
|
||||
import scala.util.DynamicVariable
|
||||
import scala.reflect.ClassTag
|
||||
import akka.actor.ActorSystem
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.{ Materializer, ActorMaterializer }
|
||||
import akka.http.scaladsl.client.RequestBuilding
|
||||
import akka.http.scaladsl.util.FastFuture
|
||||
import akka.http.scaladsl.server._
|
||||
|
|
@ -115,8 +115,14 @@ trait RouteTest extends RequestBuilding with RouteTestResultComponent with Marsh
|
|||
type Out = HttpRequest
|
||||
def apply(request: HttpRequest, f: HttpRequest ⇒ HttpRequest) = f(request)
|
||||
}
|
||||
implicit def injectIntoRoute(implicit timeout: RouteTestTimeout, setup: RoutingSetup,
|
||||
defaultHostInfo: DefaultHostInfo) =
|
||||
implicit def injectIntoRoute(implicit timeout: RouteTestTimeout,
|
||||
defaultHostInfo: DefaultHostInfo,
|
||||
routingSettings: RoutingSettings,
|
||||
executionContext: ExecutionContext,
|
||||
materializer: Materializer,
|
||||
routingLog: RoutingLog,
|
||||
rejectionHandler: RejectionHandler = RejectionHandler.default,
|
||||
exceptionHandler: ExceptionHandler = null) =
|
||||
new TildeArrow[RequestContext, Future[RouteResult]] {
|
||||
type Out = RouteTestResult
|
||||
def apply(request: HttpRequest, route: Route): Out = {
|
||||
|
|
@ -125,12 +131,12 @@ trait RouteTest extends RequestBuilding with RouteTestResultComponent with Marsh
|
|||
request.withEffectiveUri(
|
||||
securedConnection = defaultHostInfo.securedConnection,
|
||||
defaultHostHeader = defaultHostInfo.host)
|
||||
val ctx = new RequestContextImpl(effectiveRequest, setup.routingLog.requestLog(effectiveRequest), setup.settings)
|
||||
val sealedExceptionHandler = setup.exceptionHandler.seal(setup.settings)
|
||||
val ctx = new RequestContextImpl(effectiveRequest, routingLog.requestLog(effectiveRequest), routingSettings)
|
||||
val sealedExceptionHandler = ExceptionHandler.seal(exceptionHandler)
|
||||
val semiSealedRoute = // sealed for exceptions but not for rejections
|
||||
Directives.handleExceptions(sealedExceptionHandler) { route }
|
||||
val deferrableRouteResult = semiSealedRoute(ctx)
|
||||
deferrableRouteResult.fast.foreach(routeTestResult.handleResult)(setup.executor)
|
||||
deferrableRouteResult.fast.foreach(routeTestResult.handleResult)(executionContext)
|
||||
routeTestResult
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,4 +48,11 @@ object ExceptionHandler {
|
|||
ctx.complete(InternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sealed ExceptionHandler from the given one. Returns the default handler if the given one
|
||||
* is `null`.
|
||||
*/
|
||||
def seal(handler: ExceptionHandler)(implicit settings: RoutingSettings): ExceptionHandler =
|
||||
if (handler ne null) handler.seal(settings) else ExceptionHandler.default(settings)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
package akka.http.scaladsl.server
|
||||
|
||||
import scala.concurrent.Future
|
||||
import akka.stream.Materializer
|
||||
|
||||
import scala.concurrent.{ ExecutionContext, Future }
|
||||
import akka.stream.scaladsl.Flow
|
||||
import akka.http.scaladsl.model.{ HttpRequest, HttpResponse }
|
||||
import akka.http.scaladsl.util.FastFuture._
|
||||
|
|
@ -19,10 +21,11 @@ object Route {
|
|||
/**
|
||||
* "Seals" a route by wrapping it with exception handling and rejection conversion.
|
||||
*/
|
||||
def seal(route: Route)(implicit setup: RoutingSetup): Route = {
|
||||
def seal(route: Route)(implicit routingSettings: RoutingSettings,
|
||||
rejectionHandler: RejectionHandler = RejectionHandler.default,
|
||||
exceptionHandler: ExceptionHandler = null): Route = {
|
||||
import directives.ExecutionDirectives._
|
||||
import setup._
|
||||
handleExceptions(exceptionHandler.seal(setup.settings)) {
|
||||
handleExceptions(ExceptionHandler.seal(exceptionHandler)) {
|
||||
handleRejections(rejectionHandler.seal) {
|
||||
route
|
||||
}
|
||||
|
|
@ -34,19 +37,35 @@ object Route {
|
|||
*
|
||||
* This conversion is also implicitly available through [[RouteResult.route2HandlerFlow]].
|
||||
*/
|
||||
def handlerFlow(route: Route)(implicit setup: RoutingSetup): Flow[HttpRequest, HttpResponse, Unit] =
|
||||
def handlerFlow(route: Route)(implicit routingSettings: RoutingSettings,
|
||||
materializer: Materializer,
|
||||
routingLog: RoutingLog,
|
||||
executionContext: ExecutionContext = null,
|
||||
rejectionHandler: RejectionHandler = RejectionHandler.default,
|
||||
exceptionHandler: ExceptionHandler = null): Flow[HttpRequest, HttpResponse, Unit] =
|
||||
Flow[HttpRequest].mapAsync(1)(asyncHandler(route))
|
||||
|
||||
/**
|
||||
* Turns a `Route` into an async handler function.
|
||||
*/
|
||||
def asyncHandler(route: Route)(implicit setup: RoutingSetup): HttpRequest ⇒ Future[HttpResponse] = {
|
||||
import setup._
|
||||
val sealedRoute = seal(route)
|
||||
request ⇒
|
||||
sealedRoute(new RequestContextImpl(request, routingLog.requestLog(request), setup.settings)).fast.map {
|
||||
case RouteResult.Complete(response) ⇒ response
|
||||
case RouteResult.Rejected(rejected) ⇒ throw new IllegalStateException(s"Unhandled rejections '$rejected', unsealed RejectionHandler?!")
|
||||
}
|
||||
def asyncHandler(route: Route)(implicit routingSettings: RoutingSettings,
|
||||
materializer: Materializer,
|
||||
routingLog: RoutingLog,
|
||||
executionContext: ExecutionContext = null,
|
||||
rejectionHandler: RejectionHandler = RejectionHandler.default,
|
||||
exceptionHandler: ExceptionHandler = null): HttpRequest ⇒ Future[HttpResponse] = {
|
||||
val effectiveEC = if (executionContext ne null) executionContext else materializer.executionContext
|
||||
|
||||
{
|
||||
implicit val executionContext = effectiveEC // overrides parameter
|
||||
|
||||
val sealedRoute = seal(route)
|
||||
request ⇒
|
||||
sealedRoute(new RequestContextImpl(request, routingLog.requestLog(request), routingSettings)).fast
|
||||
.map {
|
||||
case RouteResult.Complete(response) ⇒ response
|
||||
case RouteResult.Rejected(rejected) ⇒ throw new IllegalStateException(s"Unhandled rejections '$rejected', unsealed RejectionHandler?!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
package akka.http.scaladsl.server
|
||||
|
||||
import scala.collection.immutable
|
||||
import scala.concurrent.ExecutionContext
|
||||
import akka.stream.Materializer
|
||||
import akka.stream.scaladsl.Flow
|
||||
import akka.http.scaladsl.model.{ HttpRequest, HttpResponse }
|
||||
|
||||
|
|
@ -20,6 +22,11 @@ object RouteResult {
|
|||
final case class Complete(response: HttpResponse) extends RouteResult
|
||||
final case class Rejected(rejections: immutable.Seq[Rejection]) extends RouteResult
|
||||
|
||||
implicit def route2HandlerFlow(route: Route)(implicit setup: RoutingSetup): Flow[HttpRequest, HttpResponse, Unit] =
|
||||
implicit def route2HandlerFlow(route: Route)(implicit routingSettings: RoutingSettings,
|
||||
materializer: Materializer,
|
||||
routingLog: RoutingLog,
|
||||
executionContext: ExecutionContext = null,
|
||||
rejectionHandler: RejectionHandler = RejectionHandler.default,
|
||||
exceptionHandler: ExceptionHandler = null): Flow[HttpRequest, HttpResponse, Unit] =
|
||||
Route.handlerFlow(route)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.scaladsl.server
|
||||
|
||||
import akka.event.LoggingAdapter
|
||||
import akka.actor.{ ActorSystem, ActorContext }
|
||||
import akka.http.scaladsl.model.HttpRequest
|
||||
|
||||
trait RoutingLog {
|
||||
def log: LoggingAdapter
|
||||
def requestLog(request: HttpRequest): LoggingAdapter
|
||||
}
|
||||
|
||||
object RoutingLog extends LowerPriorityRoutingLogImplicits {
|
||||
def apply(defaultLog: LoggingAdapter): RoutingLog =
|
||||
new RoutingLog {
|
||||
def log = defaultLog
|
||||
def requestLog(request: HttpRequest) = defaultLog
|
||||
}
|
||||
|
||||
implicit def fromActorContext(implicit ac: ActorContext): RoutingLog = RoutingLog(ac.system.log)
|
||||
}
|
||||
sealed abstract class LowerPriorityRoutingLogImplicits {
|
||||
implicit def fromActorSystem(implicit system: ActorSystem): RoutingLog = RoutingLog(system.log)
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.scaladsl.server
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
import akka.event.LoggingAdapter
|
||||
import akka.actor.{ ActorSystem, ActorContext }
|
||||
import akka.stream.Materializer
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.model.HttpRequest
|
||||
|
||||
/**
|
||||
* Provides a ``RoutingSetup`` for a given connection.
|
||||
*/
|
||||
trait RoutingSetupProvider {
|
||||
def apply(connection: Http.IncomingConnection): RoutingSetup
|
||||
}
|
||||
object RoutingSetupProvider {
|
||||
def apply(f: Http.IncomingConnection ⇒ RoutingSetup): RoutingSetupProvider =
|
||||
new RoutingSetupProvider {
|
||||
def apply(connection: Http.IncomingConnection) = f(connection)
|
||||
}
|
||||
|
||||
implicit def default(implicit setup: RoutingSetup) = RoutingSetupProvider(_ ⇒ setup)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides all dependencies required for route execution.
|
||||
*/
|
||||
class RoutingSetup(
|
||||
val settings: RoutingSettings,
|
||||
val exceptionHandler: ExceptionHandler,
|
||||
val rejectionHandler: RejectionHandler,
|
||||
val executionContext: ExecutionContext,
|
||||
val materializer: Materializer,
|
||||
val routingLog: RoutingLog) {
|
||||
|
||||
// enable `import setup._` to properly bring implicits in scope
|
||||
implicit def executor: ExecutionContext = executionContext
|
||||
implicit def implicitMaterializer: Materializer = materializer
|
||||
}
|
||||
|
||||
object RoutingSetup {
|
||||
implicit def apply(implicit routingSettings: RoutingSettings,
|
||||
exceptionHandler: ExceptionHandler = null,
|
||||
rejectionHandler: RejectionHandler = null,
|
||||
executionContext: ExecutionContext = null,
|
||||
materializer: Materializer,
|
||||
routingLog: RoutingLog): RoutingSetup =
|
||||
new RoutingSetup(
|
||||
routingSettings,
|
||||
if (exceptionHandler ne null) exceptionHandler else ExceptionHandler.default(routingSettings),
|
||||
if (rejectionHandler ne null) rejectionHandler else RejectionHandler.default,
|
||||
if (executionContext ne null) executionContext else materializer.executionContext,
|
||||
materializer,
|
||||
routingLog)
|
||||
}
|
||||
|
||||
trait RoutingLog {
|
||||
def log: LoggingAdapter
|
||||
def requestLog(request: HttpRequest): LoggingAdapter
|
||||
}
|
||||
|
||||
object RoutingLog extends LowerPriorityRoutingLogImplicits {
|
||||
def apply(defaultLog: LoggingAdapter): RoutingLog =
|
||||
new RoutingLog {
|
||||
def log = defaultLog
|
||||
def requestLog(request: HttpRequest) = defaultLog
|
||||
}
|
||||
|
||||
implicit def fromActorContext(implicit ac: ActorContext): RoutingLog = RoutingLog(ac.system.log)
|
||||
}
|
||||
sealed abstract class LowerPriorityRoutingLogImplicits {
|
||||
implicit def fromActorSystem(implicit system: ActorSystem): RoutingLog = RoutingLog(system.log)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue