JBY
JBY

Reputation: 238

How do I add filters for WebSocket requests in Play Framework

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

Answers (1)

JBY
JBY

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

Related Questions