如何在Scala Play中管理国家!2.0 Websockets?

Mar*_*ark 4 scala enumerator websocket iterate playframework-2.0

我正在查看https://github.com/playframework/Play20/tree/master/samples/scala/websocket-chat上的示例

要制作一个websocket控制器,你可以这样写:

def chat(username: String) = WebSocket.async[JsValue] { request  =>
    ChatRoom.join(username)
}  
Run Code Online (Sandbox Code Playgroud)

Chatroom.join返回一个scala.concurrent.Future [(Iteratee [JsValue,_],Enumerator [JsValue])].但是在Play中使用的iteratee和枚举器在哪里!框架?该网页套接字类(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
}
Run Code Online (Sandbox Code Playgroud)

怎么玩!在消耗输入时管理iteratee的变化状态?

Jam*_*pic 5

值得注意的是,它WebSocket本身只是一个愚蠢的容器.魔术发生在各种类中play.core.server.netty.

要理解这个魔法是什么,查看f的签名是有益的(WebSocket包含的函数:

RequestHeader => (Enumerator[A], Iteratee[A, Unit]) => Unit
Run Code Online (Sandbox Code Playgroud)

这是一个带a RequestHeader,an Enumerator和an 的函数Iteratee,并用它们做一些事情.

因此,在未来的某个时刻,框架将为我们WebSocket提供一个RequestHeader(应该是自我解释的),一个Enumerator[A](枚举器是来源,在这种情况下,这些是从客户端接收的消息),并且Iteratee[A, Unit](Iteratees是接收器,在这种情况下,这是我们发送消息返回客户端的地方).

在这种情况下WebSocket.adapter,WebSocket将连接EnumeratorIterateevia Enumeratee.在这种情况下WebSocket.using,WebSocket将远程连接Enumerator到本地Iteratee,并将remove连接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
    }
  }
Run Code Online (Sandbox Code Playgroud)

请注意,此代码几乎肯定存在线程安全问题 - 在Scala中,您应该尽可能避免使用可变状态,或者如果没有则使用actor或类似代码.

或者,尝试WebSocket.using,看看pushee Enumerator,与foreach一起Iteratee,虽然它是一个小小的提琴手.也许可以理解,pushee枚举器在Play 2.1中被弃用,因为它被新的频道系统所取代.