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
}

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

4

1 回答 1

5

值得注意的是,它WebSocket本身只是一个愚蠢的容器。魔法发生在play.core.server.netty.

要了解这种魔法是什么,看一下 f 的签名(aWebSocket包含的函数:

RequestHeader => (Enumerator[A], Iteratee[A, Unit]) => Unit

这是一个函数,它接受 a RequestHeader、 anEnumerator和 an Iteratee,并对它们做一些事情。

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

在 的情况下,WebSocket.adapterWebSocket 将Enumerator通过. 在这种情况下,WebSocket 会将远程连接到本地,并将删除连接到本地。IterateeEnumerateeWebSocket.usingEnumeratorIterateeIterateeEnumerator

与直接定义 WebSocket 相比,使用对象中的一种便捷方法可能更容易WebSocket。以下代码将回显收到的上一条消息:

  def mySocket = WebSocket.adapter {implicit req =>
    var lastMessage = "No previous message"
    Enumeratee.map[String] {msg =>
      val response = lastMessage
      lastMessage = msg
      response
    }
  }

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

或者,尝试WebSocket.using并查看 pusheeEnumerator和 foreach Iteratee,尽管它有点小问题。或许可以理解,在 Play 2.1 中不推荐使用 pushee 枚举器,因为它正在被新的通道系统所取代。

于 2012-12-24T21:25:18.443 回答