Last active
December 22, 2015 21:19
-
-
Save gakuzzzz/6532349 to your computer and use it in GitHub Desktop.
Play2.2 ActionBuilder extended
This file contains hidden or 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 play.api.mvc | |
import play.api.libs.iteratee._ | |
import play.api._ | |
import scala.concurrent._ | |
import scala.language.higherKinds | |
import scalaz.Id._ | |
trait ActionBuilder[R[_], I[_]] { | |
self => | |
final def apply[A](bodyParser: BodyParser[A])(block: R[I[A]] => Result): Action[I[A]] = async(bodyParser) { req: R[I[A]] => | |
block(req) match { | |
case simple: SimpleResult => Future.successful(simple) | |
case async: AsyncResult => async.unflatten | |
} | |
} | |
final def apply(block: R[I[AnyContent]] => Result): Action[I[AnyContent]] = apply(BodyParsers.parse.anyContent)(block) | |
final def apply(block: => Result): Action[I[AnyContent]] = apply(_ => block) | |
final def async(block: => Future[SimpleResult]): Action[I[AnyContent]] = async(_ => block) | |
final def async(block: R[I[AnyContent]] => Future[SimpleResult]): Action[I[AnyContent]] = async(BodyParsers.parse.anyContent)(block) | |
final def async[A](bodyParser: BodyParser[A])(block: R[I[A]] => Future[SimpleResult]): Action[I[A]] = new Action[I[A]] { | |
def parser: BodyParser[I[A]] = composeParser(bodyParser) | |
def apply(request: Request[I[A]]) = try { | |
invokeBlock(request, block) | |
} catch { | |
case e: NotImplementedError => throw new RuntimeException(e) | |
case e: LinkageError => throw new RuntimeException(e) | |
} | |
override def executionContext = ActionBuilder.this.executionContext | |
} | |
def invokeBlock[A](request: Request[I[A]], block: R[I[A]] => Future[SimpleResult]): Future[SimpleResult] = block(fromRequest(request)) | |
def unwrap[A](request: Request[I[A]]): Request[A] | |
def toRequest[A](request: R[I[A]]): Request[I[A]] | |
def fromRequest[A](request: Request[I[A]]): R[I[A]] | |
def composeParser[A](bodyParser: BodyParser[A]): BodyParser[I[A]] | |
def >>[R2[_], I2[_]](builder: ActionBuilder[R2, I2]): ActionBuilder[R2, ({type L[B] = I2[I[B]]})#L] = new ActionBuilder[R2, ({type L[B] = I2[I[B]]})#L] { | |
override def invokeBlock[A](request: Request[I2[I[A]]], block: R2[I2[I[A]]] => Future[SimpleResult]): Future[SimpleResult] = { | |
builder.invokeBlock(request, { req1: R2[I2[I[A]]] => | |
ActionBuilder.this.invokeBlock(builder.unwrap(builder.toRequest(req1)), { req2: R[I[A]] => | |
val req3: R2[I2[I[A]]] = ??? // generate req3 from req1 and req2 | |
block(req3) | |
}) | |
}) | |
} | |
def unwrap[A](request: Request[I2[I[A]]]): Request[A] = ActionBuilder.this.unwrap(builder.unwrap(request)) | |
def toRequest[A](request: R2[I2[I[A]]]): Request[I2[I[A]]] = builder.toRequest(request) | |
def fromRequest[A](request: Request[I2[I[A]]]): R2[I2[I[A]]] = builder.fromRequest(request) | |
def composeParser[A](bodyParser: BodyParser[A]): BodyParser[I2[I[A]]] = { | |
builder.composeParser(ActionBuilder.this.composeParser(bodyParser)) | |
} | |
} | |
protected def executionContext: ExecutionContext = play.api.libs.concurrent.Execution.defaultContext | |
} | |
object Stack { | |
val MyAction = AuthAction >> IpCheckAction >> LoggigAction >> CsrfAction | |
} | |
object Action extends ActionBuilder[Request, Id] { | |
def unwrap[A](request: Request[A]): Request[A] = request | |
def toRequest[A](request: Request[A]): Request[A] = request | |
def fromRequest[A](request: Request[A]): Request[A] = request | |
def composeParser[A](bodyParser: BodyParser[A]): BodyParser[A] = bodyParser | |
} | |
class User(id: Int, name: String) | |
object AuthAction extends ActionBuilder[Request, ({type L[A] = (A, User)})#L] { | |
def unwrap[A](request: Request[(A, User)]): Request[A] = request.map(_._1) | |
def toRequest[A](request: Request[(A, User)]): Request[(A, User)] = request | |
def fromRequest[A](request: Request[(A, User)]): Request[(A, User)] = request | |
import play.api.libs.concurrent.Execution.Implicits.defaultContext | |
def composeParser[A](bodyParser: BodyParser[A]): BodyParser[(A, User)] = BodyParser { | |
req => Iteratee.flatten(authorized(req).map { | |
case Right(user) => bodyParser.map((_, user))(req) | |
case Left(result) => Done[Array[Byte], Either[SimpleResult, (A, User)]](Left(result)) | |
}) | |
} | |
private def authorized(request: RequestHeader)(implicit context: ExecutionContext): Future[Either[SimpleResult, User]] = | |
??? // do authentication and authorization | |
} | |
object IpCheckAction extends ActionBuilder[Request, Id] { | |
def unwrap[A](request: Request[A]): Request[A] = request | |
def toRequest[A](request: Request[A]): Request[A] = request | |
def fromRequest[A](request: Request[A]): Request[A] = request | |
def composeParser[A](bodyParser: BodyParser[A]): BodyParser[A] = BodyParser { | |
req => if (checkIp(req)) Done[Array[Byte], Either[SimpleResult, A]](Left(invalidIpResult)) | |
else bodyParser(req) | |
} | |
private def checkIp(request: RequestHeader): Boolean = ??? // do IP check | |
private def invalidIpResult: SimpleResult = Results.Forbidden | |
} | |
object LoggigAction extends ActionBuilder[Request, Id] { | |
def unwrap[A](request: Request[A]): Request[A] = request | |
def toRequest[A](request: Request[A]): Request[A] = request | |
def fromRequest[A](request: Request[A]): Request[A] = request | |
def composeParser[A](bodyParser: BodyParser[A]): BodyParser[A] = bodyParser | |
override def invokeBlock[A](request: Request[A], block: Request[A] => Future[SimpleResult]): Future[SimpleResult] = { | |
Logger.info("action start") | |
block(request).andThen { | |
case _ => Logger.info("action end") | |
} (executionContext) | |
} | |
} | |
class RequestWithToken[A](val token: String, request: Request[A]) extends WrappedRequest(request) | |
object CsrfAction extends ActionBuilder[RequestWithToken, Id] { | |
def unwrap[A](request: Request[A]): Request[A] = request | |
def toRequest[A](request: RequestWithToken[A]): Request[A] = request | |
def fromRequest[A](request: Request[A]): RequestWithToken[A] = new RequestWithToken("random generate", request) | |
def composeParser[A](bodyParser: BodyParser[A]): BodyParser[A] = bodyParser | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment