§Using chunked responses with Comet

A common use of chunked responses is to create a Comet socket.

A Comet socket is a chunked text/html response containing only <script> elements. For each chunk, we write a <script> tag containing JavaScript that is immediately executed by the web browser. This way we can send events live to the web browser from the server: for each message, wrap it into a <script> tag that calls a JavaScript callback function, and write it to the chunked response.

Because Ok.chunked leverages Akka Streams to take a Flow[ByteString], we can send a Flow of elements and transform it so that each element is escaped and wrapped in the Javascript method. The Comet helper automates Comet sockets, pushing an initial blank buffer data for browser compatibility, and supporting both String and JSON messages.

§Comet Imports

To use the Comet helper, import the following classes:

import play.api.http.ContentTypes
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.libs.Comet
import play.api.libs.iteratee.Enumerator
import play.api.libs.json._
import play.api.libs.streams.Streams
import play.api.mvc._

You will also need a materializer, which is best done by pulling from your DI system.

§Using Comet with String Flow

To push string messages through a Flow, do the following:

def cometString = Action {
  implicit val m = materializer
  def stringSource: Source[String, _] = Source(List("kiki", "foo", "bar"))
  Ok.chunked(stringSource via Comet.string("parent.cometMessage")).as(ContentTypes.HTML)

§Using Comet with JSON Flow

To push JSON messages through a Flow, do the following:

def cometJson = Action {
  implicit val m = materializer
  def jsonSource: Source[JsValue, _] = Source(List(JsString("jsonString")))
  Ok.chunked(jsonSource via Comet.json("parent.cometMessage")).as(ContentTypes.HTML)

§Using Comet with iframe

The comet helper should typically be used with a forever-iframe technique, with an HTML page like:

<script type="text/javascript">
  var cometMessage = function(event) {
    console.log('Received event: ' + event)

<iframe src="/comet"></iframe>

For an example of a Comet helper, see the Play 2.5 Clock Template.

§Debugging Comet

The easiest way to debug a Comet stream that is not working is to use the log() operation to show any errors involved in mapping data through the stream.

§Legacy Comet with Enumerator

Previously existing Comet functionality is still available through an Enumeratee using Comet.apply, but it is deprecated and you are encouraged to move to the Akka Streams based version.

If you have existing code that relies heavily on Enumerator, you can use play.api.libs.streams.Streams and the interoperability with Reactive Streams to convert an Enumerator to a Stream:

def cometFromEnumerator = Action {
  implicit val m = materializer
  val enum = Enumerator("one", "two", "three")
  val publisher = Streams.enumeratorToPublisher(enum)
  def stringSource: Source[String, _] = Source.fromPublisher(publisher)
  Ok.chunked(stringSource via Comet.string("parent.cometMessage")).as(ContentTypes.HTML)

Also see the Streams Migration Guide.

Next: WebSockets

Found an error in this documentation? The source code for this page can be found here. After reading the documentation guidelines, please feel free to contribute a pull request.