BroadcastHub filtering based on “resource” the connected client is working on?

早过忘川 提交于 2019-12-04 06:03:45

I would actually recommend using Play's socket.io support. This offers namespaces, which from what I can tell from your description make it straight forward to implement exactly what you want - each namespace is its own independently managed flow, but all namespaces go down the same WebSocket. I wrote a blog post about why you might choose to use socket.io today.

If you don't want to use socket.io, I have an example here (this uses socket.io, but doesn't use socket.io namespaces, so could easily be adapted to run on straight WebSockets) which shows a multi chat room protocol - it feeds messages into a BroadcastHub, and then there is one subscription to the hub for each chat room that the user is currently a part of (for you, it would be one subscription for each project). Each of those subscriptions filter the messages from the hub to include only the messages for that subscriptions chat room, and then feed the messages into that chatrooms MergeHub.

The highlighted code here is not specific to socket.io at all, if you can adapt the WebSocket connection to be a flow of ChatEvent, you can use this as is:

https://github.com/playframework/play-socket.io/blob/c113e74a4d9b435814df1ccdc885029c397d9179/samples/scala/multi-room-chat/app/chat/ChatEngine.scala#L84-L125

To address your requirement to direct non project specific messages through a broadcast channel that everyone connects to, first, create that channel:

val generalFlow = {
  val (sink, source) = MergeHub.source[NonProjectSpecificEvent]
    .toMat(BroadcastHub.sink[NonProjectSpecificEvent])(Keep.both).run
  Flow.fromSinkAndSourceCoupled(sink, source)
}

Then, when the broadcast sink/source for each connected WebSocket connects, attach it (this is from the chat example:

} via {
  Flow.fromSinkAndSourceCoupledMat(BroadcastHub.sink[YourEvent], MergeHub.source[YourEvent]) { (source, sink) =>
    broadcastSource = source
    mergeSink = sink

    source.filter(_.isInstanceOf[NonProjectSpecificEvent])
      .via(generalFlow)
      .runWith(sink)

    NotUsed
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!