3

現在 Play WebSocket メッセージを処理しているクライアントにプライベート応答を送信する必要がありますが、他のメッセージについては、すべてのクライアントに応答をブロードキャストする必要があります。

Play チャットの例では、着信メッセージはただちに 1 つの Actor にオフロードされます。

case Connected(enumerator) => 
  // Create an Iteratee to consume the feed, assuming all requests have
  // a JSON "text" node, and delegate all to the Akka Actor:
  val iteratee = Iteratee.foreach[JsValue] { event =>
    default ! Talk(username, (event \ "text").as[String])
  }.map { _ =>
    default ! Quit(username)
  }
  (iteratee,enumerator)

上記では、接続が承認されると、同じアクタによって既に作成されenumeratorた単一のものが参照されます。chatEnumerator

val (chatEnumerator, chatChannel) = Concurrent.broadcast[JsValue]

これでは、1 つのクライアントだけにメッセージを送信することはできないと思いますか? ブロードキャスト機能を削除し、各クライアントの列挙子を作成して追跡し、自分自身を反復する必要がありますか? または、どうにかしてクライアント固有の列挙子への参照を取得できますforeachか?

(組み込みの柔軟性は実装に依存することを理解していますが、このユースケースは私には非常に一般的なようです。Socket.IOで WebSockets を使用する場合と同様に、すべてのクライアント、現在の送信者を除くすべてのクライアントにメッセージ簡単に送信できますリクエスト、または単一のクライアント.これは、私が Play 2.1.x でも達成しようとしていることです。)

4

2 に答える 2

2

1 つの方法は、を使用して 2 つの列挙子をインターリーブすることEnumerator.interleaveです。

したがって、ブロードキャスト用とプライベート接続用の 2 つのペアを作成し、インターリーブすること(Enumerator, Channel)ができます。Concurrent.broadcast(またはConcurrent.unicast、プライベート列挙子に使用するだけかもしれませんが、使用方法がわかりませんでした。)

これは play 2.3.0 で動作するサンプルの play コードです。

object Application extends Controller {
  val (publicOut,publicChannel) = Concurrent.broadcast[String]
  def chat = WebSocket.using[String]{ request =>
    val (privateOut,privateChannel) = Concurrent.broadcast[String]
    val in = Iteratee.foreach{
      msg:String => if(msg.startsWith("@")){
        publicChannel.push("Broadcasted: " + msg)
      }else{
        privateChannel.push("Private: " + msg)
      }
    }
    val out = Enumerator.interleave(publicOut,privateOut)
    (in, out)
  }
}

特定のクライアントにメッセージを送信するのは少し複雑なコードになりますが、概念は同じです。ActorWebSocket ごとのペアを保持する を作成(Enumerator, Channel)し、アクターにメッセージを送信します。

于 2014-06-23T00:57:52.213 に答える