我正在尝试将此代码转换为使用Play版本2.4到当前版本(2.6)并且我遇到了一些问题,因为我仍然是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)
}
我跟着this guide,但现在我停留在应该返回方法的东西上。 这是我试图使用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)
}
但是我在运行服务器时遇到了这个错误,指向方法的第一行:
could not find implicit value for parameter transformer: play.api.mvc.WebSocket.MessageFlowTransformer[String,scala.concurrent.Future[String]]
注意:我也尝试拨打WebSocket.apply
而不是WebSocket.accept
,我搜索了两者之间的差异,但没有找到任何有用的信息。有人可以解释两者之间的区别吗?感谢。
答案 0 :(得分:2)
表面错误是Play不知道如何将Future[String]
转换为Websocket消息,您通常会使用隐式转换器。但是,在这种情况下,您无论如何都不想返回Future[String]
,而只是一个可以自动编组的简单字符串(使用提供的stringMessageFlowTransformer
。)这里有' s应该有用的东西:
def wsWeatherIntervals = WebSocket.accept[String, String] { res =>
val url = "http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl"
def f = ws.url(url).get().map(r => s"${new java.util.Date()}\n ${r.body}")
val source = Source.unfoldAsync(f)(last => {
Thread.sleep(3000)
f.map(next => Some((last, next)))
})
Flow.fromSinkAndSource(Sink.ignore, source)
}
unfoldAsync
源允许我们重复运行一个函数,返回流中下一个元素的未来。 (由于我们希望流永远继续,我们返回包含为Some
的值。)
Websocket.apply
方法基本上是accept
的一个更复杂的版本,它允许你通过返回响应来拒绝websocket连接,但是如果你需要这样做,那么它就是这样做的。最好使用acceptOrResult
,它处理将流发出的任何内容转换为websocket消息。