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! 内で使用される iteratee と列挙子はどこにありますか? フレームワーク?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

これは、RequestHeaderEnumerator、およびを受け取り、Iterateeそれらを処理する関数です。

したがって、将来のある時点で、フレームワークはWebSocketRequestHeader(これは自明であるはずです)、Enumerator[A](列挙子はソースであり、この場合、これらはクライアントから受信されるメッセージです)、およびIteratee[A, Unit](Iteratees はシンク (この場合、これはクライアントに戻るメッセージを送信する場所です)。

の場合WebSocket.adapter、WebSocket は を 経由で に接続EnumeratorIterateeますEnumeratee。の場合WebSocket.using、WebSocket はリモートEnumeratorをローカルIterateeに接続し、削除Iterateeをローカルに接続しEnumeratorます。

WebSocket を直接定義するよりも、WebSocketオブジェクト内の便利なメソッドの 1 つを使用する方が簡単である可能性があります。次のコードは、受信した前のメッセージをエコーし​​ます。

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

このコードには、ほぼ確実にスレッド セーフの問題があることに注意してください。Scala では、可能であれば変更可能な状態を避けるようにしてください。そうでない場合は、アクターなどを使用する必要があります。

または、試してみて、 foreach と組み合わせてWebSocket.usingpushee を見てください。当然のことかもしれませんが、Play 2.1 では pushee 列挙子が非推奨になりました。これは、新しいチャネル システムに取って代わられているためです。EnumeratorIteratee

于 2012-12-24T21:25:18.443 に答える