将 Play 框架中的 WebSockets 从版本 2.4 转换为 2.6

Converting WebSockets in Play framework from version 2.4 to 2.6

我正在尝试将这段使用 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,但现在我卡在了我应该 return 方法上的东西上。 这是我尝试 运行 使用版本 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,我搜索了两者之间的差异,但没有找到任何有用的信息。有人可以解释两者之间的区别吗?谢谢。

表面错误是 Play 不知道如何将 Future[String] 转换为 Websocket 消息,您通常会为此使用隐式转换器。但是,在这种情况下,您不想 return 一个 Future[String] ,而只是一个可以自动编组的普通字符串(碰巧使用提供的 stringMessageFlowTransformer 。)这是一些东西应该工作:

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 源代码让我们重复 运行 一个函数 returning 流中下一个元素的未来。 (因为我们希望流永远持续下去,所以我们 return 将值包装为 Some。)

Websocket.apply 方法基本上是 accept 的更复杂版本,它允许您出于某种原因通过 returning 响应来拒绝 websocket 连接,但是如果您需要这样做最好使用 acceptOrResult,它负责将您的流发出的任何内容转换为 websocket 消息。