我正在使用Http4s挂载一个websocket服务,我可以用它在这个后端服务和UI之间进行通信(管道状态更新和批处理作业的完成%)。
我正在使用BlazeBuilder Websocket Example来设置服务。
该服务有效,但我尝试做的是从类实例中发出套接字消息。例如,我想实例化一个worker,传递一个socket连接的引用,并能够将数据发送到该连接。不幸的是,我很难完成这项工作!它在Python和JS中要简单得多。
请参阅下面的代码,该代码主要是我上面链接的示例代码。在我调用Stream.emit(...)的地方,如何将引用传递给#34; toClient"并仍然向它发射?如果我将toClient实例传递给类实例,它似乎无法工作。
case GET -> Root / "ws" =>
val toClient: Stream[F, WebSocketFrame] = Stream.emit(Text("How can I do this from a class instance?"))
val fromClient: Sink[F, WebSocketFrame] = _.evalMap { (ws: WebSocketFrame) =>
ws match {
case Text(t, _) => F.delay(println(t))
case f => F.delay(println(s"Unknown type: $f"))
}
}
WebSocketBuilder[F].build(toClient, fromClient)
答案 0 :(得分:0)
您可以使用MVar与Websocket进行线程安全通信。
以下是使用Cats IO效果的示例:
final class WebSocketServer(implicit timer: Timer[IO]) extends Http4sDsl[IO] {
implicit val contextShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
def start: IO[ExitCode] = {
BlazeServerBuilder[IO]
.bindHttp(8080)
.withWebSockets(true)
.withHttpApp(routes.orNotFound)
.resource
.use(_ => IO.never)
.as(ExitCode.Success)
}
private[this] val routes: HttpRoutes[IO] = HttpRoutes.of[IO] {
case GET -> Root / "ws" => {
for {
channel <- cats.effect.concurrent.MVar[IO].empty[List[WebSocketFrame]]
webSocket <- {
WebSocketBuilder[IO].build(
send = fs2.Stream
.eval(channel.take)
.flatMap(fs2.Stream.emits(_))
.repeat,
receive = stream => {
stream.evalMap {
case Text(data, _) => channel.put(List(Text("pong")))
case unknown => IO(println(s"Unknown type: $unknown"))
}
}
)
}
} yield webSocket
}
}
}
如果要将消息发送回客户端,则必须将其放入MVar。
channel.put(List(Text("pong")))
有趣的部分是重复流,该流正在MVar中轮询新消息,以将新消息发送回WebSocket的客户端。
fs2.Stream.eval(channel.take).flatMap(fs2.Stream.emits(_).repeat