In our project we are using ReactiveMongo
with Play 2.2.1
.
The problem is, that to stream of data in a form of Enumerator[A]
, returned by ReactiveMongo
is actually a stream of value objects, which are not separated by commas, and do not have stream beginning and end annotations, which can be treated as array opening and close statements.
This creates a problem for JSON
consumer JS client
, since the expected format is
[A1,A2, ...]
So we jumped in hoops, and transformed our Enumeratee[A]
to Enumerator[String]
, with checking, if it's the first element, or not:
var first:Boolean = true
val aToStrs = (as.map(a => {
if(first) {
first = false;
Json.stringify(Json.toJson(a))
} else {
"," + Json.stringify(Json.toJson(a))
}
}))
Ok.chunked(
Enumerator.enumInput(Input.El("[")) andThen
aToStrs andThen
Enumerator.enumInput(Input.El("]")) andThen
Enumerator.enumInput(Input.EOF)
)
This works, but feels like inventing the wheel.
Is there a better solution, for this common problem?
If you use comet or EventSource you wont have to hand craft a way to generate output and you will also actually be able to parse the response item for item in the client. Responding with an array would force you to either write your own parsing code or wait until everything has arrived on the client side before you can use the build int JSON parser in your JavaScript.
Streaming with the EventSource protocol is pretty easy with play, you should be able to do something like:
implicit val cometEncoder = new Comet.CometMessage[JsValue](_.toString)
Ok.chunked(yourEnumerator &> EventSource()).as(EVENT_STREAM)
And then in the client html:
<script type="text/javascript">
var es = new EventSource(jsRouter.controllers.Application.streamIt().url)
es.addEventListener("message", function (event) {
var item = JSON.parse(event.data)
// ... do something with the json value ...
})
</script>
There is an example of this in the play sample projects that you might want to look at as well $YOUR_PLAY_DIR/samples/scala/eventsource-clock/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With