Scala Play! 2.0中Websockets的状态是如何管理的?

4
我正在查看https://github.com/playframework/Play20/tree/master/samples/scala/websocket-chat上的示例。
要创建一个 WebSocket 控制器,你需要编写类似下面的代码:
def chat(username: String) = WebSocket.async[JsValue] { request  =>
    ChatRoom.join(username)
}  

Chatroom.join返回一个scala.concurrent.Future[(Iteratee[JsValue,_],Enumerator[JsValue])]。但是在Play!框架中,迭代器和枚举器在哪里使用?WebSocket类(WebSocket.scala)似乎忽略了这些输入:
case class WebSocket[A](f: RequestHeader => (Enumerator[A], Iteratee[A, Unit]) => Unit)        (implicit val frameFormatter: WebSocket.FrameFormatter[A]) extends Handler {

  type FRAMES_TYPE = A

  /**
   * Returns itself, for better support in the routes file.
   *
   * @return itself
   */
   def apply() = this
}

Play! 如何管理迭代器消耗输入时的状态变化?
1个回答

5
值得注意的是,WebSocket 本身只是一个简单的容器。真正的魔力来自于 play.core.server.netty 中的各种类。
要理解这个魔力是什么,看一下 f 的签名就很有启发性(f 是 WebSocket 包含的函数)。
RequestHeader => (Enumerator[A], Iteratee[A, Unit]) => Unit

这是一个函数,它接受RequestHeaderEnumeratorIteratee作为参数,并对它们进行某些操作。
因此,在将来的某个时间点,框架将向我们的WebSocket提供一个RequestHeader(应该是不言自明的)、一个Enumerator[A](在本例中,这些是从客户端接收到的消息的来源)和一个Iteratee[A,Unit](在本例中,迭代器是汇聚器,这是我们发送消息返回到客户端的地方)。
WebSocket.adapter的情况下,WebSocket将通过Enumeratee连接EnumeratorIteratee。在WebSocket.using的情况下,WebSocket将连接远程的Enumerator到本地的Iteratee,并连接远程的Iteratee到本地的Enumerator
与其直接定义WebSocket,使用WebSocket对象中的便捷方法可能更容易。以下代码将回显先前接收到的消息:
  def mySocket = WebSocket.adapter {implicit req =>
    var lastMessage = "No previous message"
    Enumeratee.map[String] {msg =>
      val response = lastMessage
      lastMessage = msg
      response
    }
  }

请注意,这段代码几乎肯定存在线程安全问题 - 在Scala中,您应该尽可能避免可变状态,或者如果不行,使用actors或类似的东西。
或者,尝试使用WebSocket.using,并查看push Enumerator,与foreach Iteratee一起使用,虽然有点复杂。也许可以理解的是,在Play 2.1中,推送枚举器已被弃用,因为它正在被新的通道系统取代。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接