Skip to content

Instantly share code, notes, and snippets.

@AitorATuin
Created June 1, 2014 13:57
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AitorATuin/c94d06e34ae45ee5d880 to your computer and use it in GitHub Desktop.
Save AitorATuin/c94d06e34ae45ee5d880 to your computer and use it in GitHub Desktop.
Jetty Async Plans with Directives Support for Unfiltered
import unfiltered.response._
import unfiltered.request._
import unfiltered.filter._
import unfiltered.directives._
import Directive._
import scala.concurrent.Future
import scala.util.Try
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
object AsyncDirective {
type AsyncDirectiveResponse[A,B] = (HttpRequest[A] => Result[ResponseFunction[B], AsyncResponse[B]])
type AsyncRequest[A,B] = HttpRequest[A] with unfiltered.Async.Responder[B]
trait AsyncResponse[A] {
val future: Future[A]
val onComplete: Try[A] => ResponseFunction[A]
def !(f: ResponseFunction[A] => Unit) = future.onComplete(onComplete.andThen(f))
}
object AsyncResponse {
def apply[A](f: Future[A])(func: Try[A] => ResponseFunction[A]) = new AsyncResponse[A] {
val future = f
val onComplete = func
}
}
def apply[A, B](intent: PartialFunction[HttpRequest[A], AsyncDirectiveResponse[A,B]]): async.Plan.Intent = {
case req: AsyncRequest[A,B] if intent.isDefinedAt(req) => intent(req)(req) match {
case Result.Success(asyncResponse) => asyncResponse ! (req.respond _)
case Result.Failure(response) => req.respond(response)
case Result.Error(response) => req.respond(response)
}
}
}
import unfiltered.filter._
import unfiltered.directives._
import Directive._
import scala.concurrent.Future
import scala.util.Try
object TestAsyncDirective {
import AsyncDirective._
def myfuture(delay: Int) =
Future {
Thread.sleep(delay)
println("<future>")
"future "
}
val directiveIntent = AsyncDirective[Any, String] {
case Path(Seg("test" :: "tres" :: Nil)) => for {
_ <- GET
delay <- data.as.Int.fail { (k, v) =>
BadRequest ~> ResponseString(
s"'$v' is not a valid int for $k"
)
} named "delay"
request <- Directives.request[Any]
v <- Directive((_: HttpRequest[Any]) => Result.Success(myfuture(delay.getOrElse(5000))))
} yield AsyncResponse(v) {
case scala.util.Success(v) => Ok ~> ResponseString("async directive succeded with value: " + v)
case scala.util.Failure(t) => BadRequest ~> ResponseString("Error processing request")
}
}
object AsyncPlan extends unfiltered.filter.async.Plan {
def intent = directiveIntent
}
def main(args: Array[String]) {
unfiltered.jetty.Http.local(8080).filter(AsyncPlan).run()
}
}
@kareblak
Copy link

We've tried to approach the problem with the use of Directives as a monad wrapper. Works like a charm and it's not limited to Futures.

https://github.com/shiplog/directives2

@AitorATuin
Copy link
Author

nice! I will take a look to your approach, thanks for the advise!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment