我正在尝试学习如何使用WebSockets和Akka,使用Play for Scala一书中的聊天示例。
在书中,创建了一个"聊天室",它在聊天控制器中实例化,内容如下:
val room = Akka.system.actorOf(Props[ChatRoom])
我想扩展此示例,并有多个聊天室可用,而不仅仅是一个。用户可以提供一个字符串,该字符串可以是聊天室"名称",这将创建一个新的聊天室。任何尝试加入此聊天室的人都会相互共享广播,但不会与另一个聊天室中的人共享广播。与IRC非常相似。
我的问题如下:
1: 如果尚不存在唯一名称的聊天室,如何创建该聊天室?2:如何检查现有聊天室是否存在并获取对它的引用?
聊天室名称将通过 URL 或查询参数提供,该部分将微不足道。我只是不完全确定如何唯一地识别 Akka 聊天室,然后按名称检索该 Actor。
您可以在 Akka 中命名演员,因此无需:
Akka.system.actorOf(Props[ChatRoom])
您将拥有:
Akka.system.actorOf(Props[ChatRoom],"room1")
然后,根据您使用的 Akka 版本,使用 Akka.system.actorFor("room1")
或 Akka.system.actorSelection("room1")
获取对所需聊天室的引用。
使用 Akka EventBus 特性。您可以使用 eventBus 和 LookupClassification 来实现基于主题的发布-订阅,其中"主题"是房间 ID,订阅者是每个房间的参与者或每个客户端的 Web 套接字参与者。
import akka.event.EventBus
import akka.event.LookupClassification
final case class MsgEnvelope(topic: String, payload: Any)
/**
* Publishes the payload of the MsgEnvelope when the topic of the
* MsgEnvelope equals the String specified when subscribing.
*/
class LookupBusImpl extends EventBus with LookupClassification {
type Event = MsgEnvelope
type Classifier = String
type Subscriber = ActorRef
// is used for extracting the classifier from the incoming events
override protected def classify(event: Event): Classifier = event.topic
// will be invoked for each event for all subscribers which registered themselves
// for the event’s classifier
override protected def publish(event: Event, subscriber: Subscriber): Unit = {
subscriber ! event.payload
}
// must define a full order over the subscribers, expressed as expected from
// `java.lang.Comparable.compare`
override protected def compareSubscribers(a: Subscriber, b: Subscriber): Int =
a.compareTo(b)
// determines the initial size of the index data structure
// used internally (i.e. the expected number of different classifiers)
override protected def mapSize: Int = 128
}
然后注册你的演员(实际上,你会统计每个房间有多少用户,并在用户进入房间时订阅,当房间内没有人时取消订阅并杀死演员)
val lookupBus = new LookupBusImpl
lookupBus.subscribe(room1Actor, "room1")
lookupBus.subscribe(room2Actor, "room2")
消息将根据房间 ID 进行切换
lookupBus.publish(MsgEnvelope("room1", "hello room1"))
lookupBus.publish(MsgEnvelope("room2", "hello room2"))
lookupBus.publish(MsgEnvelope("room3", "hello dead letter"))