将 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 消息。
我正在尝试将这段使用 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 消息。