Как использовать Play2 Iteratees для использования потокового HTTP с разными именами событий?
Мне нужен функциональный способ потребления отправленных сервером событий (SSE) по HTTP (или потокового HTTP, как некоторые его называют). На примерах ( Scala: Receiving Server-Sent-Events) я обнаружил, что итераторы Play2 хорошо работают со своим клиентом WS, когда для имени события установлено "message". Вот как выглядит поток "сообщений":
GET http://streaming.server.com/temperature
event: message
data: {"room":"room1","temp":71,"time":"2015-05-06T00:23:10.203+02:00"}
event: message
data: {"room":"room1","temp":70,"time":"2015-05-06T00:31:18.873+02:00"}
...
А вот как выглядит мой веб-клиент:
import com.ning.http.client.AsyncHttpClientConfig.Builder
import play.api.libs.iteratee.Iteratee
import play.api.libs.iteratee.Execution.Implicits.defaultExecutionContext
import play.api.libs.ws.ning.NingWSClient
object Client extends App {
val client = new NingWSClient(new Builder().build())
def print = Iteratee.foreach { chunk: Array[Byte] => println(new String(chunk)) }
client.url("http://streaming.server.com/temperature").get(_ => print)
}
с выводом, который он напечатал на моей консоли:
$ sbt run
[info] Running Client
data: {"room":"room1","temp": 70, "time":"2015-05-06T00:31:14.193+02:00"}
data: {"room":"room1","temp": 70, "time":"2015-05-06T00:31:18.873+02:00"}
...
Но когда я устанавливаю для "события" какое-либо иное значение, чем "сообщение", Итератор немедленно возвращает Done
сигнал только после чтения первого значения, а затем останавливает поток. Спецификация, которую я должен удовлетворить, использует "event":"put"
, Ниже приведен пример того, как выглядит поток "put":
GET http://streaming.server.com/temperature
event: put
data: {"room":"room1","temp":71,"time":"2015-05-06T00:39:14.281+02:00"}
event: put
data: {"room":"room1","temp":70,"time":"2015-05-06T00:39:18.778+02:00"}
...
Я обнаружил это, когда я добавил onComplete()
обработчик в конце и соответствует на Success
бывает так:
client.url("http://streaming.server.com/temperature").get(_ => print).onComplete {
case Success(s) => println(s)
case Failure(s) => println(f.getMessage)
}
Этот код теперь печатает:
$ sbt run
[info] Running Client
data: {"room":"room1","temp": 71, "time":"2015-05-06T00:39:14.281+02:00"}
Done((),Empty)
До сих пор я имел успех только с библиотекой Джерси для Java, семантика которой очень похожа на JavaScript-клиент EventSource; однако он не скомпонован и, по-видимому, поддерживает только однопоточное потребление SSE. Я бы предпочел использовать библиотеки Play2 WS+Iteratee. Как мне этого добиться?