Scala: Receiving Server-Sent-Events

2020-06-16 02:27发布

问题:

Set-up:

A project I am working on has a pub/sub server with an HTTP interface. Subscription works by accepting server-sent-events.

curl -X GET server:port/topics/news

which will be pushed whenever a message is published to the given topic URL

curl -X PUT server:port/topics/news -d "Politician Lies!"

Problem:

I have a scala project which needs to subscribe to this pub/sub server. The Play! framework is able to handle this by using PlayWS with Enumeratee + Iteratee. Unfortunately, the PlayWS library requires that a Play! Application is in scope and I am not using Play. Is there a library (with minimal dependancies) I can use which allows me to accept server-sent-events? I'll need at least one working example in order to get started.

I have a preference for scala libraries but I'm willing to accept a Java solution if I have to.

回答1:

You have several possibilities:

In Play 2.3, the WS library is now a separate library, so that should help. RC2 is already available

Alternatively, you could depend on Play 2.x and use a StaticApplication like so:

val application = new StaticApplication(new java.io.File("."))

This will essentially bootstrap a Play application, and from there on you can use the WS library as usual



回答2:

I've accepted Manuel Bernhardt's answer because it led me in the right direction but I feel a full example is important for anyone else with this issue.

I updated my build.sbt file to include PlayWS 2.3 and the Iteratees library.

libraryDependencies ++= Seq(
  "com.typesafe.play" %% "play-ws" % "2.3.0",
  "com.typesafe.play" %% "play-iteratees" % "2.3.0"
)

The WS singleton requires an implicit Play Application to be used (something I don't have or want) so instead I will need to create my own client

val builder = new (com.ning.http.client.AsyncHttpClientConfig.Builder)()
val client = new play.api.libs.ws.ning.NingWSClient(builder.build())

I then create my Iteratee so that I can handle my server-sent-events.

def print = Iteratee.foreach { chunk: Array[Byte] => 
  println(new String(chunk))
}

and finally subscribe to the server

client.url("http://localhost:8080/topics/news").get(_ => print)

Now, when an event is sent

curl -X PUT server:port/topics/news -d "Politician Lies!"

My Scala application will print the received event

data: Politician Lies!


回答3:

I'm not aware of other Scala libraries that implement a Server Sent Events client, but the Jersey project has a Java library for Server Sent Events clients (as well as servers). The API does not appear to be very verbose, and appears like it can be nicely wrapped in some code to fit in more idiomatically with Scala.