Reputation: 238
Using Play 2.5.3, I have this filter setup:
@Singleton
class Filters @Inject() (
env: Environment,
postRequestLoggingFilter: PostRequestLoggingFilter) extends HttpFilters {
override val filters = {
Seq(postRequestLoggingFilter)
}
}
This works great for regular http web requests, but does not trigger for a WebSocket route (ws://) such as:
class Controller3 @Inject() (implicit system: ActorSystem, materializer: Materializer) extends play.api.mvc.Controller {
def socket = WebSocket.acceptOrResult[String, String] { request =>
...
How can I include this route type in my filters or is there another mechanism for intercepting this type of request?
Upvotes: 4
Views: 515
Reputation: 238
After spending some time looking into this, the way the Filter system currently works it doesn't lend itself well to being applied to WebSocket requests.
The issue is that Filters work with an apply method taking a
nextFilter: RequestHeader => Future[Result]
where as WebSocket functions take a
f: RequestHeader => Future[Either[Result, Flow[In, Out, _]]]
So passing the WebSocket result through the Filter system doesn't really work.
However for my case, I was primarily interested in the logging filter. So as a workaround I created a custom version of acceptOrResult
as follows:
def acceptOrResult[TIn, TOut](f: RequestHeader => Future[Either[Result, Flow[TIn, TOut, _]]])(implicit transformer: MessageFlowTransformer[TIn, TOut], materializer: Materializer, ec: ExecutionContext): WebSocket = {
WebSocket { request =>
f(request).map { fResult =>
PostRequestLoggingFilter.apply(request,fResult.left.getOrElse(Ok))
fResult.right.map(transformer.transform)
}
}
}
I needed to break the logic out of the PostRequestLoggingFilter
into it's companion object's apply method so the above could function.
If the WebSocket
request is Left
, we have a Result
; if it's Right
then I just pass an Ok
result. This could be applied to other filters as long as you don't mind the fact that they'll run after the WebSocket request.
Upvotes: 4