I'm trying to convert this code, that uses the Play version 2.4 to the current version (2.6) and I'm having some issues because I'm still a noob in Scala.
def wsWeatherIntervals = WebSocket.using[String] {
request =>
val url = "http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl"
val outEnumerator = Enumerator.repeatM[String]({
Thread.sleep(3000)
ws.url(url).get().map(r => s"${new java.util.Date()}\n ${r.body}")
})
(Iteratee.ignore[String], outEnumerator)
}
I followed this guide, but now I'm stuck on the stuff that I should return on the method. This is the code that I'm trying to run using the version 2.6:
import play.api.mvc._
import scala.concurrent.Future
import akka.stream.scaladsl._
def wsWeatherIntervals = WebSocket.accept[String, Future[String]] { res =>
val url = "http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl"
val source = Source.repeat({
Thread.sleep(3000)
ws.url(url).get().map(r => s"${new java.util.Date()}\n ${r.body}")
})
Flow.fromSinkAndSource(Sink.ignore, source)
}
But I'm getting this error when running the server, that points to the first line of the method:
could not find implicit value for parameter transformer: play.api.mvc.WebSocket.MessageFlowTransformer[String,scala.concurrent.Future[String]]
Note: I also tried to call WebSocket.apply instead of WebSocket.accept and I did some search about the differences between the two but didn't find anything useful. Can someone explain the difference between the two? Thanks.
The superficial error is that Play doesn't know how to turn a
Future[String]into a Websocket message, for which you'd normally use an implicit transformer. However, in this case you don't want to return aFuture[String]anyway but just a plain string which can be automatically marshalled (using the providedstringMessageFlowTransformeras it happens.) Here's something that should work:The
unfoldAsyncsource lets us repeated run a function returning a future of the next element in the stream. (Since we want the stream to go on forever we return the value wrapped asSome.)The
Websocket.applymethod is basically a more complicated version ofacceptwhich allows you to reject a websocket connection for some reason by returning a response, but if you need to do this it's better to useacceptOrResult, which handles transforming whatever your flow emits into websocket messages.